类型模式匹配为什么变量是必须的

Type pattern match why a variable is a must

我正在阅读 "Scala for Impatient 2nd" 第 14.4 节,我对上下文感到困惑:

You can match on the type of an expression, for example :

obj match {
   case x:Int => x
   case s:String => Integer.parseInt(s)
   case _:BigInt => Int.MaxValue
   case _ => 0
}

When you match against a type, you must supply a variable name. Otherwise, you match the object :

obj match {
   case _:BigInt => Int.MaxValue // Matches any object of type BigInt
   case BigInt => -1 // Matches the BigInt object of type Class
}

我感到困惑的是如何理解作为 expression 请求的 obj : 如果我测试如下:

val x = 121
val obj : Any = x
obj == 121 // true

obj match {
   case x:Int => x
   case s:String => Integer.parseInt(s)
   case _:BigInt => Int.MaxValue
   case _ => 0
} // res133: Int = 121

但是,如果我只是将整数值分配给 obj,编译器会抛出错误:

val obj2 = 121
obj2 == 121 // true

obj2 match {
   case x:Int => x
   case s:String => Integer.parseInt(s)
   case _:BigInt => Int.MaxValue
   case _ => 0
} // <console>:22: error : scrutinee is incompatible with pattern type;
found : String
required : Int
    case s : String => Integer.parseInt(s)
             ^    
<console>:23: error : scrutinee is incompatible with pattern type;
found : BigInt
required : Int
    case _ : BigInt => Int.MaxValue
             ^      

唯一的区别是前一个例子我用另一个变量赋值obj,而后一个例子我用一个整数值赋值obj。为什么后一个例子会出现编译错误?

问题更新:我理解 "compiler knows that obj2 is Int",但是,我认为这就是 match 表达式的作用,因为 obj2Int 并且它遇到了第一个 match 子句 case x:Int => x 因此匹配成功并且整个匹配表达式完成。我认为这应该和前面的例子完全一样,唯一的区别是这两个变量是 AnyInt 类型,但是它们都匹配了第一个匹配子句并且它们都应该是正确编译。

根据本书第 14.4 节 "In Scala, this (type pattern) match is preferred to using the isInstanceOf operator",我认为使用类型模式是一种识别对象类型的方法。如果我们知道对象类型,那么 "type pattern" 有什么用?

第二个问题是我对下面的上下文感到困惑。如何理解 "object of type BigInt" v.s "BigInt object of type Class" ? "type Class" 与 java generic/reflection 概念相关吗?

obj match {
   case _:BigInt => Int.MaxValue // Matches any object of type BigInt
   case BigInt => -1 // Matches the BigInt object of type Class
}

谢谢!

由于类型推断,第二个赋值缺少类型归属

val obj2 = 121

使 obj2 成为 Int,而不是

val obj : Any = x

这使它成为 Any

在第二种情况下,编译器知道 obj2Int,因此它知道 StringBigInt 的匹配不可能成功.


这里在编译时已知的和在 运行 时已知的是有区别的。您有以下代码:

val x = 121
val obj: Any = x

在 运行 时,xobj 都是 Int 并且将匹配您的 match 表达式中的第一个案例。

在编译时,编译器知道 xInt,因此它知道没有必要测试 StringBigInt。它所知道的 objAny,因此可以检查 StringBigInt 或任何其他类型。

现在在这种情况下,很明显编译器可以计算出 obj 实际上是 Int,但在一般情况下这是不可能的。编译器没有关于类型推断的复杂规则,而是使用程序员为值 Any 提供的类型。因此它假定 obj 可能是 StringBigInt 即使在这种情况下从代码中可以明显看出它不是。

How to understand "object of type BigInt" v.s "BigInt object of type Class" ? is "type Class" related to java generic/reflection concept ?

这只是书中的一个错误。 BigInt 模式(即 case BigInt => ...)匹配声明为

companion object
object BigInt { ... }

在代码中。它是不是类型Class;它的类型 is written as BigInt.type,但很少有用。

所以如果你写

val x: Any = BigInt

x match {
  case _: BigInt => // doesn't match
  case BigInt => // matches
}

val x: Any = new BigInt(...) 将匹配第一个而不是第二个。