Scala: смешайте черты характера и класс case в сопоставлении с образцом

Я хочу сопоставить несколько классов кейсов. Если я их не знаю, я хочу сопоставить по указанному признаку, который классы должны расширять. Это похоже

trait Event  //root trait
trait Status extends Event  //special trait
trait UIEvent extends Event //special trait

case class Results extends Event   //concrete case class
case class Query extends Event     //concrete case class

case class Running extends Status  //concrete case class
case class Finished extends Status //concrete case class

case class Update extends UIEvent  //concrete case class

Я провожу следующий тест

  val events = List(Results, Query, Running, Finished, Update)
    events foreach {
      case Results => println("Got a Results")
      case Running => println("Got a Running")
      case s:Status => println("Got some StatusEvent")
      case ui:UIEvent => println("Got some UIEvent")
      case e: Event => println("Generic Event")
      case x => println("Didn't matched at all " + x)
    }
    println("############################")
    val STATUS = classOf[Status]
    val EVENT = classOf[Event]
    val UIEVENT = classOf[UIEvent]
    val RESULTS = classOf[Results]
    val eventsClass = events map (_.getClass)
    eventsClass foreach {
      case RESULTS => println("Got a Results")
      case STATUS => println("Got some StatusEvent")
      case UIEVENT =>  println("Got some UIEvent")
      case EVENT => println("Generic Event")
      case x => println("Didn't matched at all " + x)
    }

что приводит к следующему выводу

Got a Results
Didn't match at all Query
Got a Running
Didn't match at all Finished
Didn't match at all Update
############################
Didn't match at all class de.mukis.scala.test.main.Results$
Didn't match at all class de.mukis.scala.test.main.Query$
Didn't match at all class de.mukis.scala.test.main.Running$
Didn't match at all class de.mukis.scala.test.main.Finished$
Didn't match at all class de.mukis.scala.test.main.Update$

Почему я не могу сопоставить образец по классу case и трейтам или только по классу?


person Muki    schedule 29.09.2011    source источник


Ответы (2)


Проблема в том, что вы имеете в виду сопутствующие объекты для классов дел, а не их конкретные экземпляры. В связи с этим REPL уже должен был выдать вам предупреждения об устаревании.

Решение - добавить несколько скобок:

sealed abstract trait Event
sealed abstract trait Status extends Event
sealed abstract trait UIEvent extends Event

case class Results() extends Event
case class Query() extends Event

case class Running() extends Status
case class Finished() extends Status

case class Update() extends UIEvent

и

val events = List(Results(), Query(), Running(), Finished(), Update())
events foreach {
  case Results() => println("Got a Results")
  case Running() => println("Got a Running")
  case s:Status => println("Got some StatusEvent")
  case ui:UIEvent => println("Got some UIEvent")
  case e: Event => println("Generic Event")
  case x => println("Didn't match at all " + x)
}

или, как предлагает Дидьерд, используйте case objects

sealed abstract trait Event
sealed abstract trait Status extends Event
sealed abstract trait UIEvent extends Event

case object Results extends Event
case object Query extends Event

case object Running extends Status
case object Finished extends Status

case object Update extends UIEvent

и

val events = List(Results, Query, Running, Finished, Update)
events foreach {
  case Results => println("Got a Results")
  case Running => println("Got a Running")
  case s:Status => println("Got some StatusEvent")
  case ui:UIEvent => println("Got some UIEvent")
  case e: Event => println("Generic Event")
  case x => println("Didn't match at all " + x)
}
person Kevin Wright    schedule 29.09.2011
comment
согласно stackoverflow.com/a/9349191/409976, abstract в trait является избыточным. Поскольку это избыточно, я полагаю, что это безвредно. Но есть ли особая причина, по которой вы включили его сюда, @Kevin? - person Kevin Meredith; 04.07.2014

Ваша проблема связана с классом case без скобок (которые теперь устарели). Класс case подразумевает создание сопутствующего объекта. Когда вы пишете Результаты без скобок как в вашем списке, так и в сопоставлении с образцом, это означает сопутствующий объект.

Вы можете попробовать

define sortOut(x: Any) = x match {
  case Results => "companion object"
  case Results() => "instance"
}

sortOut(Results) // returns companion object
sortout(Results()) // returns instance

Это объясняет поведение во второй части. Поскольку Results является сопутствующим объектом, Results.getClass() не является classOf [Results], который является классом экземпляра, а (синтетическим) классом сопутствующего объекта, Results$

Если case class не имеет параметров, в большинстве случаев это означает, что различные экземпляры нельзя отличить друг от друга, и вам лучше использовать case object. В противном случае ставьте скобки.

person Didier Dupont    schedule 29.09.2011
comment
спасибо за быстрый ответ. Где я могу найти эти изменения, какой стиль кода устарел, а какой нет (я, к счастью, где-то читал, что наследование класса case не рекомендуется). - person Muki; 29.09.2011
comment
Я не знал, что он устарел, прежде чем отмечать sortOut в ответе, просто знал, что это опасно. Я не смог найти его в списке изменений (некоторые ссылки в списке рассылки и stackoverflow.com/q/2254710/754787 в StackOverflow). Обратите внимание, однако, что это не изменение языка, а просто добавленное предупреждение (подразумевающее, что в будущем он может перестать поддерживаться), но поведение было таким же до прекращения поддержки. - person Didier Dupont; 29.09.2011