很明显,Unit是AnyVal的子类型。所以我尝试了这个:
object Main extends App {
val u : Unit = Seq[String]()
}
它编译得很好。但我预计会有一些错误。 DEMO
为什么呢? Unit
不是Seq
答案 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
。
以下七个隐式转换可应用于表达式
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
循环是另一个