【问题标题】:Scala: Mix traits and case class in pattern matchScala:在模式匹配中混合特征和案例类
【发布时间】:2011-11-27 14:53:29
【问题描述】:

我想匹配一些案例类。如果我不认识它们,我想匹配类必须扩展的指定特征。这看起来像

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$

为什么我不能在案例类和特征上进行模式匹配,或者只在类上进行模式匹配?

【问题讨论】:

    标签: scala pattern-matching traits case-class


    【解决方案1】:

    问题在于您指的是案例类的伴随对象,而不是它们的特定实例。因此,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)
    }
    

    或者,正如 didierd 建议的那样,使用 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)
    }
    

    【讨论】:

    • per stackoverflow.com/a/9349191/409976, abstract in trait 是多余的。既然是多余的,那么我想它是无害的。但是,@Kevin 将它包含在这里有什么特别的原因吗?
    【解决方案2】:

    您的问题是没有括号的案例类(现在已弃用)。案例类意味着创建伴随对象。当您在列表和模式匹配中编写不带括号的结果时,它表示伴随对象。

    你可以试试

    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。否则,放括号。

    【讨论】:

    • 感谢您的快速回答。我在哪里可以找到这些更改,哪些代码样式已被弃用,哪些不是(幸运的是,我在某处读到不建议使用案例类继承)。
    • 在检查 repl 中的 sortOut 之前,我不知道它已被弃用,只知道它很危险。我在 changse 列表中找不到它(邮件列表中的一些引用和 StackOverflow 上的 stackoverflow.com/q/2254710/754787)。但是请注意,这不是语言更改,只是一个附加警告(暗示将来可能会停止支持),但在弃用之前的行为是相同的。
    猜你喜欢
    • 2017-02-25
    • 2020-11-19
    • 2016-10-13
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 1970-01-01
    • 2017-04-25
    • 2020-11-28
    相关资源
    最近更新 更多