且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Scala 中类型归属的目的是什么?

更新时间:2023-01-13 23:23:38

类型归属只是告诉编译器你期望从所有可能的有效类型的表达式中得到什么类型.

Type ascription is just telling the compiler what type you expect out of an expression, from all possible valid types.

一个类型是有效的,如果它尊重现有的约束,例如变化和类型声明,并且它是它应用于表达式的类型之一is a",或者有一个转换适用范围.

A type is valid if it respects existing constraints, such as variance and type declarations, and it is either one of the types the expression it applies to "is a", or there's a conversion that applies in scope.

所以,java.lang.String 扩展了 java.lang.Object,因此任何 String 也是一个 Object.在您的示例中,您声明希望将表达式 s 视为 Object,而不是 String.由于没有任何限制阻止这种情况发生,并且所需的类型是 s is a 类型之一,因此它可以工作.

So, java.lang.String extends java.lang.Object, therefore any String is also an Object. In your example you declared you want the expression s to be treated as an Object, not a String. Since there is no constraints preventing that and the desired type is one of the types s is a, it works.

现在,你为什么想要那个?考虑一下:

Now, why would you want that? Consider this:

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)

您也可以通过在 ss 声明中键入脚本 s 来修复此问题,或者您可以将 ss 的类型声明为 设置[AnyRef].

You could also have fixed this by type ascripting s at ss declaration, or you could have declared ss's type to be Set[AnyRef].

然而,类型声明只有在为标识符赋值时才能实现相同的目的.当然,如果一个人不关心用一次性标识符来乱扔代码,那么哪个总是可以做到的.例如,以下不能编译:

However, type declarations achieve the same thing only as long as you are assigning a value to an identifier. Which one can always do, of course, if one doesn't care about littering the code with one-shot identifiers. For example, the following does not compile:

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]() ,但这并不总是一个选项.考虑一下,例如:

It would be silly to use an identifier here in place of Nil. And though I could just write List[String]() instead, that isn't always an option. Consider this, for instance:

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 日草案)关于类型归属的说明:

For the reference, this is what Scala 2.7 spec (march 15, 2009 draft) has to say about type ascription:

Expr1 ::= ...
        | PostfixExpr Ascription

Ascription ::= ‘:’ InfixType
             | ‘:’ Annotation {Annotation}
             | ‘:’ ‘_’ ‘*’