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

时间:2019-07-05 06:48:40

标签: scala pattern-matching expression generic-programming

我正在阅读“ Scala for Im耐心第二版”第14.4节,其中我对上下文感到困惑:

  

您可以匹配表达式的类型,例如:

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

与类型匹配时,必须提供变量名称。    否则,您将匹配对象:

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

我很困惑的是如何理解obj的要求expression: 如果我进行如下测试:

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。为什么后面的示例会出现编译错误?

问题更新:我知道“编译器知道obj2Int”,但是,我认为这是match表达式的作用,我,e因为obj2Int并且它满足第一个match子句case x:Int => x,所以匹配成功并且整个匹配表达式完成了。我认为这应该与前面的示例完全相同,唯一的区别是这两个变量是AnyInt类型的,但是它们都与第一个match子句匹配,并且它们都应该是正确编译。

从本书第14.4节“在Scala中,这种(类型模式)匹配比使用isInstanceOf运算符更合适”,我认为使用类型模式是一种识别对象类型的方法。如果我们知道对象类型,“类型模式”用于什么?

第二个问题是我混淆了下面的内容。如何理解“ BigInt类型的对象”与“ Class类型的BigInt对象”? “ Class类型”与java泛型/反射概念有关吗?

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

谢谢!

3 个答案:

答案 0 :(得分:5)

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


在编译时已知与运行时已知之间有区别。您具有以下代码:

val x = 121
val obj: Any = x

在运行时,xobj均为Int,并且将与match表达式中的第一种情况匹配。

在编译时,编译器知道xInt,因此知道测试StringBigInt没有意义。关于obj的所有知识就是它是Any,因此可以检查StringBigInt或任何其他类型。

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

答案 1 :(得分:3)

  

如何理解“ BigInt类型的对象”与“ Class类型的BigInt对象”? “类型类”与java泛型/反射概念有关吗?

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

companion object匹配
object BigInt { ... }

用代码表示。它不是Class类型的 not ;类型为is written as BigInt.type,但很少使用。

所以如果你写

val x: Any = BigInt

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

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

答案 2 :(得分:1)

第二项分配缺少类型说明,因此由于类型推断

val obj2 = 121

obj2设为Int,而不是

val obj : Any = x

这使它成为Any