【问题标题】:How to understand "pattern match with Singleton object" in scala?如何理解scala中的“模式匹配与单例对象”?
【发布时间】:2013-12-19 17:07:17
【问题描述】:

我的问题的上下文与论坛中其他人提出的问题相似,但我找不到完全匹配的内容,查看这些答案后我仍然是个谜。因此,如果有人可以提供帮助,我将不胜感激。我的问题的上下文是使用模式匹配来匹配单例类对象。

例如,如果我正在实现自己的列表结构,像这样

// An implementation of list
trait AList[+T] // covariant 
case class Cons[+T](val head: T, val tail: AList[T]) extends AList[T] 
case object Empty extends AList[Nothing] // singleton object

// an instance of implemented list
val xs = Cons(1, Cons(2, Cons(3, Empty)))

// pattern matching in a method - IT WORKS!
def foo[T](xs: AList[T]) = xs match {
    case Empty => "empty"
    case Cons(x, xss) => s"[$x...]"
}
println(foo(xs)) // => [1...]

// pattern matching outside - IT RAISES ERROR:
// pattern type is incompatible with expected type;  
// found   : Empty.type  
// required: Cons[Nothing]
val r: String = xs match {
    case Empty => "EMPTY"
    case Cons(x, xss) => s"[$x...]"

}
println(r) // does NOT compile

在我看来,它们在相同的“对象”上看起来是相同的“匹配”,为什么一个有效而另一个失败?我猜这个错误与匹配 expr in 和 out 方法的不同有关,但是编译器给出的消息非常具有误导性。这是否意味着我们需要在外部“匹配”时像 xs.asInstanceOf[AList[Int]] 一样显式转换 xs?

【问题讨论】:

    标签: scala singleton pattern-matching


    【解决方案1】:

    编译器告诉你xs 的类型是Cons,它不能是Empty,所以你的第一个case 是没有意义的。

    试试这个:

    val r: String = (xs: AList[Int]) match {
        case Empty => "EMPTY"
        case Cons(x, xss) => s"[$x...]"
    }
    

    或者这个:

    val ys: AList[Int] = xs
    val r: String = ys match {
        case Empty => "EMPTY"
        case Cons(x, xss) => s"[$x...]"
    }
    

    在这种情况下,编译器不知道case Empty 毫无意义。

    这正是您使用def foo[T](xs: AList[T]) = ... 所做的。 def foo[T](xs: Cons[T]) = ... 会出现同样的编译错误。

    在这个特定示例中,有效且详尽的匹配如下所示:

    val r: String = xs match {
        // case Empty => "EMPTY" // would never happened.
        case Cons(x, xss) => s"[$x...]"
    }
    

    加法:你应该让你的AList trait sealed

    sealed trait AList[+T]
    

    它允许编译器在不详尽的匹配时警告您:

    val r: String = (xs: AList[Int]) match {
      case Cons(x, xss) => s"[$x...]"
    }
    <console>:25: warning: match may not be exhaustive.
    It would fail on the following input: Empty
           val r: String = (xs: AList[Int]) match {
                              ^
    

    【讨论】:

    • 或者首先声明xsval xs: AList[Int] = ...
    • @RobStarling:在这种情况下,OP 可以删除第一个 case
    • 谢谢!那么这是否意味着在 scala 中“匹配” expr 将无法根据其案例推断最通用的类​​型并将 xs 隐式转换为 AList?例如,在 expr "1 + 1.5" 中,它的工作原理是 bcs 1 被隐式转换为浮点数?
    • @dolaameng: Int 不是Double,所以a match { case 1 =&gt; ; case 1.5 =&gt; } 适用于AnyVal 类型的aIntDouble 的公共超类)。跨度>
    【解决方案2】:

    foo 的参数是AList[T],所以在第一种情况下,匹配是在AList[T] 上完成的。在第二种情况下,匹配是在 Cons[+T] 上完成的。

    基本上匹配是在对象类型上完成的,而不是在对象上。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-26
      • 2021-11-11
      • 1970-01-01
      • 2014-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多