scala雾中风景(4): Unit类型

这个例子是一次错误的尝试时发现的,通常我们不太会用Unit类型声明参数,更多情况它是出现在函数类型声明里的出参部分(如 String=>Unit)。这个例子仅用作案例分析,先考虑下面的方法执行结果会如何?

scala> def foo(p:Unit) = {println("hi")}
foo: (p: Unit)Unit

scala> foo(2)

直觉上,感觉编译会报错,类型不匹配么,声明Unit类型,传入的确实Int类型。

实际上尝试一下会发现,它编译和运行都很正常。甚至无所谓你传入几个参数,或什么类型:

scala> foo(2,3,"OK")
hi

都能正常运行,看起来太诡异了。这背后隐含了编译器对Unit类型变量在赋值时的处理逻辑。

Unit类型是值类型,全局只存在唯一的值:()

scala> val a:Unit = ()
a: Unit = ()

若尝试把其它类型的值赋给它,也ok:

scala> val a:Unit = 2
a: Unit = ()    // 暂忽略编译器的警告,跟我们要关注的无关

诊断一下:

$ scala -nocompdaemon -Xprint:typer  -e 'val a:Unit = 2'
… 
private[this] val a: Unit = {
    2;
    ()  // 编译器自动增加了一个Unit的值:()
};
…

原因是编译对待等号右边的表达式,看待成为“行为”,会把这段“行为”统一放入花括号里。
并判断最后一句表达式的值是不是Unit类型的,如果不是则自动增加一个值:()

所以等号右边的 2 最终被转化为 { 2; () } 所以 foo(2,3,"OK") 也是被翻译为了

foo( {(2, 3, "OK"); ()} )

参数封装在一个tuple里,在最后返回一个 ()

再探究一步,Unit类型通常是用于声明方法返回值的,比如:

def foo:Unit = 2

它被翻译为:

def foo: Unit = {
    2;
    () // 编译器判断结果返回不是Unit类型的话,自动在最后返回()
}

当Unit用在值的类型时,编译器保持与方法一致的处理逻辑。

小结:通常Unit只用来声明函数或方法的返回值,其他场景基本是没有意义的。

scala雾中风景(4): Unit类型》上有6个想法

  1. Pingback引用通告: scala雾中风景(8): 高阶函数与Unit的谜题 | 在路上

  2. Pingback引用通告: scala雾中风景(17): toSet()的谜题 | 在路上

  3. Pingback引用通告: scala雾中风景(21): auto-tupling与auto-detupling | 在路上

  4. scala> reify(val a = 2)
    :1: error: illegal start of simple expression
    reify(val a = 2)

    竟然不对,看来val a:Unit = 2不是表达式(expression)而是个赋值语句(statement)导致的?

发表评论

电子邮件地址不会被公开。 必填项已用*标注