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


75

规范中没有太多有关类型归属的信息,并且当然没有关于目的的任何信息。除了“使传递的varargs起作用”之外,我还要使用类型归属?以下是一些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

Answers:


81

类型说明只是告诉编译器,从所有可能的有效类型中,表达式期望什么类型。

如果类型遵守现有的约束(例如方差和类型声明),则它是有效的,并且它是表达式所应用的类型之一是“”,或者存在适用于范围的转换。

因此,java.lang.String extends java.lang.Object因此String也是Object。在您的示例中,您声明希望将表达式s视为Object,而不是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}
             | ‘:’ ‘_’ ‘*’

28

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

val x = 2 : Byte

远比

val x = 2.asInstanceOf[Byte]

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


1
嘿,学到了新东西。我做了很多不幸的网络协议工作。很高兴知道!
贾斯汀W 2010年

21
为什么不使用日常语法?val x: Byte = 2
Jerry101

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]的更详细的形式


为什么不x.foldLeft[List[Int]](Nil)( (acc,elem) => elem::acc )呢?
杰弗里·阿奎莱拉

0

如果有些麻烦,您可能会发现此线程发光。需要注意的重要一点是,您正在向类型检查器添加约束提示-它使您可以更多地控制编译阶段的工作。


:)我在这里转发了我的问题,以便将其保留下来;我选择的答案是我最清楚的那个问题之一
davetron5000 2010年

对不起,刚刚看到了这个。做完了
贾斯汀W

0

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

Type Ascription:明确表示某种事物的类型称为Type Ascription。它可以带来什么不同?

例如: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]

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.