类型归属只是告诉编译器你期望从表达式中得到什么类型,来自所有可能的有效类型。
一个类型是有效的,如果它尊重现有的约束,例如方差和类型声明,并且它是它所应用的表达式“是 a ”的类型之一,或者存在适用于范围的转换。
所以, java.lang.String extends java.lang.Object
, 因此 anyString
也是一个Object
. 在您的示例中,您声明希望将表达式s
视为 an Object
,而不是 a String
。由于没有限制阻止这种情况,并且所需的类型s
是 a类型之一,因此它可以工作。
现在,你为什么想要那个?考虑一下:
scala> val s = "Dave"
s: java.lang.String = Dave
scala> val p = s: Object
p: java.lang.Object = Dave
scala> val ss = scala.collection.mutable.Set(s)
ss: scala.collection.mutable.Set[java.lang.String] = Set(Dave)
scala> val ps = scala.collection.mutable.Set(p)
ps: scala.collection.mutable.Set[java.lang.Object] = Set(Dave)
scala> ss += Nil
<console>:7: error: type mismatch;
found : scala.collection.immutable.Nil.type (with underlying type object Nil)
required: java.lang.String
ss += Nil
^
scala> ps += Nil
res3: ps.type = Set(List(), Dave)
您也可以通过s
在ss
声明时键入脚本来解决此问题,或者您可以将ss
的类型声明为Set[AnyRef]
。
然而,类型声明只有在为标识符赋值时才能达到同样的效果。当然,如果一个人不关心用一次性标识符乱扔代码,那总是可以做到的。例如,以下内容无法编译:
def prefixesOf(s: String) = s.foldLeft(Nil) {
case (head :: tail, char) => (head + char) :: head :: tail
case (lst, char) => char.toString :: lst
}
但这确实:
def prefixesOf(s: String) = s.foldLeft(Nil: List[String]) {
case (head :: tail, char) => (head + char) :: head :: tail
case (lst, char) => char.toString :: lst
}
在这里使用标识符代替 . 是愚蠢的Nil
。尽管我可以改写List[String]()
,但这并不总是一种选择。考虑一下,例如:
def firstVowel(s: String) = s.foldLeft(None: Option[Char]) {
case (None, char) => if ("aeiou" contains char.toLower) Some(char) else None
case (vowel, _) => vowel
}
作为参考,这是 Scala 2.7 规范(2009 年 3 月 15 日草案)关于类型归属的内容:
Expr1 ::= ...
| PostfixExpr Ascription
Ascription ::= ‘:’ InfixType
| ‘:’ Annotation {Annotation}
| ‘:’ ‘_’ ‘*’