81

规范中没有太多关于类型归属的信息,当然也没有关于它的目的的任何信息。除了“使传递可变参数起作用”之外,我会使用类型归属来做什么?下面是一些 scala REPL 的语法和使用它的效果。

scala> val s = "Dave"
s: java.lang.String = Dave

scala> val p = s:Object
p: java.lang.Object = Dave

scala> p.length
<console>:7: error: value length is not a member of java.lang.Object
       p.length
         ^
scala> p.getClass
res10: java.lang.Class[_ <: java.lang.Object] = class java.lang.String

scala> s.getClass
res11: java.lang.Class[_ <: java.lang.Object] = class java.lang.String

scala> p.asInstanceOf[String].length
res9: Int = 4
4

5 回答 5

86

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

一个类型是有效的,如果它尊重现有的约束,例如方差和类型声明,并且它是它所应用的表达式“是 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)

您也可以通过sss声明时键入脚本来解决此问题,或者您可以将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}
             | ‘:’ ‘_’ ‘*’
于 2010-01-18T16:06:35.703 回答
28

一种可能性是当网络和串行协议级别的东西时,那么:

val x = 2 : Byte

比干净得多

val x = 2.asInstanceOf[Byte]

第二种形式也是运行时转换(不由编译器处理),可能导致一些有趣的上溢/下溢条件。

于 2010-01-18T16:18:19.330 回答
0

你可能会发现这个线程很有启发性,如果有点复杂的话。需要注意的重要一点是,您正在向类型检查器添加约束提示 - 它使您可以更好地控制编译阶段正在做什么。

于 2010-01-21T03:29:52.450 回答
0

我使用类型归属来解决 Scala 类型推断中的漏洞。例如,对类型 A 的集合的 foldLeft 采用类型 B 的初始元素和用于将集合的元素折叠到初始元素中的函数 (B, A) => B。类型 B 的实际值是从初始元素的类型推断出来的。由于 Nil 扩展了 List[Nothing],因此将其用作初始元素会导致问题:

scala> val x = List(1,2,3,4)
x: List[Int] = List(1, 2, 3, 4)

scala> x.foldLeft(Nil)( (acc,elem) => elem::acc)
<console>:9: error: type mismatch;
 found   : List[Int]
 required: scala.collection.immutable.Nil.type
              x.foldLeft(Nil)( (acc,elem) => elem::acc)
                                                 ^

scala> x.foldLeft(Nil:List[Int])( (acc,elem) => elem::acc )
res2: List[Int] = List(4, 3, 2, 1)

或者,您可以只使用 List.empty[Int] 而不是 Nil:List[Int]。

scala> x.foldLeft(List.empty[Int])( (acc,elem) => elem::acc )
res3: List[Int] = List(4, 3, 2, 1)

编辑: List.empty[A] 被实现为

override def empty[A]: List[A] = Nil

(来源)

这实际上是 Nil:List[A] 的一种更详细的形式

于 2014-04-02T16:33:33.687 回答
0

类型推断:我们可以跳过在源代码中明确给出某事物的类型名称,称为类型推断。(尽管在某些特殊情况下需要。)

类型说明:明确说明某物的类型称为类型说明。它可以带来什么不同?

例如:val x = 2:字节

另请参阅: 1. 我们可以显式地为函数指定返回类型

def t1 : Option[Option[String]] = Some(None)

> t1: Option[Option[String]]

另一种声明方式可能是:

def t2 = Some(None: Option[String])
> t2: Some[Option[String]]

这里我们没有Option[Option[String]]明确给出返回类型,编译器将其推断为Some[Option[String]]. 为什么Some[Option[String]]是因为我们在定义中使用了类型归属。

  1. 我们可以使用相同定义的另一种方法是:

    def t3 = Some(None)

    > t3: Some[None.type]

这次我们没有明确告诉编译器任何事情(也没有这个 defi)。它推断我们的定义为 Some[None.type]

于 2017-06-02T15:46:51.593 回答