问题 Scala:参数化中具有完全限定类名的模式匹配问题


当使用完全限定的类名参数化时,我在Scala中的对象模式匹配中遇到一些问题。这基于Scala 2.9.0.1。谁知道这段代码有什么问题?

scala> "foo" match {
 | case y : Seq[Integer] =>
 | case y : Seq[java.lang.Integer] =>
<console>:3: error: ']' expected but '.' found.
   case y : Seq[java.lang.Integer] =>

为什么第一个版本有效,但后者失败了?当完全限定的类名用于参数化时,似乎只会出现此问题。


10535
2017-09-14 08:53


起源



答案:


来自 Scala语言规范,8.1节模式,后面的标识符:需要是8.2节中定义的类型模式:

类型模式由类型,类型变量和通配符组成。一种   pattern T是以下形式之一:

...

参数化类型模式T [a(1),. 。 。 ,a(n)],其中a(i)是   类型变量模式或通配符_。这种类型模式匹配所有   对于某种类型的任意实例化,匹配T的值   变量和通配符。这些类型的边界或别名类型   变量如(§8.3)中所述确定。

...

类型变量模式是一个以a开头的简单标识符   小写字母。但是,预定义的基元类型别名   unit,boolean,byte,short,char,int,long,float和double不是   归类为类型变量模式。

因此,从语法上讲,您不能将完全限定的类用作此位置中的类型变量模式。但是,您可以使用类型别名,因此:

type JavaInt = java.lang.Integer
List(new java.lang.Integer(5)) match {
    case y: Seq[JavaInt] => 6
    case _ => 7
}

将按预期返回6。问题在于Alan Burlison指出,以下内容也会返回6:

List("foobar") match {
    case y: Seq[JavaInt] => 6
    case _ => 7
}

因为类型正在被删除。您可以通过使用-unchecked选项运行REPL或scalac来查看此信息。


12
2017-09-14 12:55



哇。我今天打了这个,最终发现了这个问题。我不知道在Scala中甚至存在“类型变量模式”这样的事情。还有什么东西还在SLS中隐藏起来......? - Seth Tisue
一些复活节彩蛋仅在1/4和复活节上激活。 - Adriaan Moors
我在这个问题上开始了一个主题 groups.google.com/d/msg/scala-language/2PNDjkI47Ao/MCQw7RzNUwcJ - Seth Tisue
现在有一张票 issues.scala-lang.org/browse/SI-7985 ; Martin Odersky说这是一个解析器bug - Seth Tisue


答案:


来自 Scala语言规范,8.1节模式,后面的标识符:需要是8.2节中定义的类型模式:

类型模式由类型,类型变量和通配符组成。一种   pattern T是以下形式之一:

...

参数化类型模式T [a(1),. 。 。 ,a(n)],其中a(i)是   类型变量模式或通配符_。这种类型模式匹配所有   对于某种类型的任意实例化,匹配T的值   变量和通配符。这些类型的边界或别名类型   变量如(§8.3)中所述确定。

...

类型变量模式是一个以a开头的简单标识符   小写字母。但是,预定义的基元类型别名   unit,boolean,byte,short,char,int,long,float和double不是   归类为类型变量模式。

因此,从语法上讲,您不能将完全限定的类用作此位置中的类型变量模式。但是,您可以使用类型别名,因此:

type JavaInt = java.lang.Integer
List(new java.lang.Integer(5)) match {
    case y: Seq[JavaInt] => 6
    case _ => 7
}

将按预期返回6。问题在于Alan Burlison指出,以下内容也会返回6:

List("foobar") match {
    case y: Seq[JavaInt] => 6
    case _ => 7
}

因为类型正在被删除。您可以通过使用-unchecked选项运行REPL或scalac来查看此信息。


12
2017-09-14 12:55



哇。我今天打了这个,最终发现了这个问题。我不知道在Scala中甚至存在“类型变量模式”这样的事情。还有什么东西还在SLS中隐藏起来......? - Seth Tisue
一些复活节彩蛋仅在1/4和复活节上激活。 - Adriaan Moors
我在这个问题上开始了一个主题 groups.google.com/d/msg/scala-language/2PNDjkI47Ao/MCQw7RzNUwcJ - Seth Tisue
现在有一张票 issues.scala-lang.org/browse/SI-7985 ; Martin Odersky说这是一个解析器bug - Seth Tisue


实际上你的第一个例子也不起作用。如果使用-unchecked运行REPL,您将看到以下错误:

警告:非变量类型参数类型模式中的整数Seq [Integer]未被选中,因为它被擦除消除

所以你实际上无法做你想要做的事情 - 在运行时,List [Integer]和List [AnythingElse]之间没有区别,所以你不能对它进行模式匹配。您可以使用Manifest执行此操作,请参阅 http://ofps.oreilly.com/titles/9780596155957/ScalasTypeSystem.html#Manifests 和 http://www.scala-blogs.org/2008/10/manifests-reified-types.html


3
2017-09-14 10:25



我不认为类型擦除是问题的重点。这个怎么样: "foo".asInstanceOf[Any] match { <BR/> case x: Seq[Integer] => <BR/> case y: Seq[java.lang.Integer] => <BR/> } - Jamil
@Jamil,我相信 Seq[java.lang.Integer] 只是一个语法错误。我相信编译器正在对待 java.lang.Integer 作为标识符,他们不能有点。你可以通过周围来证明这一点 java.lang.Integer 在反引号中 - 然后它会编译,但你仍然会得到与plain一样的擦除警告 Integer。我同意这个错误是误导性的,但考虑到你无法真正做到@Frank试图做的事情,这并不奇怪。 - Alan Burlison
java.lang.Integer 是一种不是变量的类型。此外,当您使用构造函数模式或元组或序列等时,Scala绑定到变量。奇怪的是,如果我使用别名 type myint = java.lang.Integer 斯卡拉不抱怨 - Jamil
@Jamil,我知道它是一种类型,这就是重点 - 编译器期待变量并尝试解释 java.lang.Integer 作为一个,但它不是一个有效的变量名称,因为它有点。 - Alan Burlison