Scala类型层次结构

时间:2017-06-27 12:06:33

标签: scala types

我查看了Scala类型层次结构 enter image description here

很明显,Unit是AnyVal的子类型。所以我尝试了这个:

object Main extends App {

    val u : Unit = Seq[String]()

}

它编译得很好。但我预计会有一些错误。 DEMO

为什么呢? Unit不是Seq

的超类型

2 个答案:

答案 0 :(得分:4)

这是因为Unit也可以从语句中推断出来(与表达式相反)。这意味着如果使用Unit类型注释,编译器将忽略表达式中的最后一个值,并在实际代码后返回Unit

您可以通过将u转换回其原始类型来简单地对此进行测试。您将收到强制转换错误,因为u实际上并未绑定到您的Seq

如果你在REPL中运行它会发生什么:

scala> u.asInstanceOf[Seq[String]]
java.lang.ClassCastException: scala.runtime.BoxedUnit cannot be cast to scala.collection.Seq

正如Jasper-M正确指出的那样,编译器会将其重写为

val u: Unit = { Seq[String](); () }

答案 1 :(得分:3)

  

为什么呢? Unit不是Seq

的超类型

您假设Seq已分配给u。但事实并非如此:

println(u)
# ()

如您所见,u的值为()(即Unit的唯一单例实例),而不是空Seq

这是由于Value Discarding, which is described in clause 5 of section 6.26.1 Value Conversions of the Scala Language Specification

  

以下七个隐式转换可应用于表达式e,该表达式具有某些值类型T,并且使用某些预期类型pt进行类型检查。

     

[...]

     

如果e具有某种值类型且预期类型为Unit,则e会通过将其嵌入到术语{ e; () }中而转换为预期类型。

用简单的英语而不是“Speclish”,这意味着:如果你说“这是Unit类型”,但实际上并非如此,编译器将返回()你。

Unit类型等同于语句:语句没有值。好吧,在Scala中,一切都有价值,但是我们有()这是一个无用的值,所以在其他语言中它是一个没有价值的语句,在Scala中< em>表达式,它具有无用的值。就像其他区分表达式和语句的语言一样,有语句表达式表达式语句(例如ECMAScript,Java,C,C ++,C♯),Scala有 Value Discarding ,它本质上是 Expression Statement 的模拟(即包含一个表达式,其值被丢弃的语句)。

例如,在C中你可以写

printf("Hello, World");

即使printf是一个返回size_t的函数。但是,C很乐意允许您使用printf作为语句并简单地丢弃返回值。 Scala也是如此。

这是否是一件好事是一个不同的问题。如果C强迫你写

会更好吗?
size_t ignoreme = printf("Hello, World");

或者如果Scala强迫你写

val _ = processKeyBinding​(…)
// or
{ processKeyBinding​(…); () }

而不仅仅是

processKeyBinding​(…)

我不知道。但是,Scala的设计目标之一是与主机平台很好地集成,并且只是意味着与其他语言的高性能语言互操作性,这也意味着现有开发人员的轻松入门,所以有一些Scala中的功能实际上并不需要但是为了熟悉主机平台的开发人员而存在(例如Java,C♯,ECMAScript) - Value Discarding 就是其中之一,while循环是另一个