【发布时间】:2016-12-20 09:05:39
【问题描述】:
Unit 在生成字节码时由编译器进行特殊处理,因为它类似于 jvm 上的void。但从概念上讲,作为 scala 类型系统中的一种类型,它似乎在语言本身中也得到了特殊处理(下面的示例)。
所以我的问题是要澄清这一点并了解使用了哪些机制以及是否真的对 Unit 类型进行了特殊处理。
示例 1:
对于像Seq这样的“普通”scala类型,如果一个方法返回Seq,那么你必须返回Seq(或更具体的扩展Seq的类型)
def foo1: Seq[Int] = List(1, 2, 3)
def foo2: Seq[Int] = Vector(1, 2, 3)
def foo3: Seq[Int] = "foo" // Fails
前两个示例编译是因为List[Int] 和Vector[Int] 是Seq[Int] 的子类型。第三个失败,因为String 不是。
但是,如果我将第三个示例更改为返回 Unit,它将编译并运行而不会出现问题,即使 String 不是 @ 的子类型987654335@:
def foo3(): Unit = "foo" // Compiles (with a warning)
我不知道在 scala 中允许此异常的任何其他类型。编译器在类型系统级别是否有针对 Unit 类型的特殊规则,或者是否有某种更通用的机制在起作用,例如隐式转换。
示例 2:
我也不清楚在通常应用方差规则的情况下单位如何交互。
例如,我们有时会在Future[Unit] 中遇到此错误,我们会不小心使用map 而不是flatMap 并创建Future[Future]:
def save(customer: Customer): Future[Unit] = ... // Save to database
def foo: Future[Unit] = save(customer1).map(_ => save(customer2))
map 正在创建Future[Future[Unit]],编译器需要Future[Unit]。然而,这编译!
起初我以为这是因为Future[+T] 是协变的,但实际上Future[Unit] 不是Unit 的子类型,所以看起来不是这样。
例如,如果类型更改为Boolean,编译器会检测到错误:
def save(customer: Customer): Future[Boolean] = ...
def foo: Future[Boolean] = save(customer1).map(_ => save(customer2)) // Compiler fails this
对于所有其他非Unit 类型,它不会编译(Any 除外,因为 Future[Any] 碰巧是 Any 的子类型)。
那么编译器在这种情况下是否有特殊规则?还是有更一般的过程发生?
【问题讨论】:
-
基本上,如果您将某种类型声明为 Unit(例如,值或函数返回),编译器会将其具有的任何值转换为 Unit。不确定这是否是您正在寻找的答案,或者您是否正在寻找更多内部细节..
标签: scala functional-programming static-typing