Null与Nothing,造型问题

Null与Nothing

scala类型系统以Any为根,分为AnyRefAnyVal 两个分支体系,在AnyRef分支的最底层,有个Null类型的特殊类型,它被当作是所有AnyRef类型的子类型。
更进一步在两个分支共同的最底层类型是Nothing类型,它被当作所有AnyRefAnyVal类型的子类型。

Null类型只有一个唯一的值:null,可以被赋给所有的AnyRef类型变量

scala> val s:String = null
s: String = null

但null不可以赋值给AnyVal类型:

scala> val i:Int = null
<console>:7: error: type mismatch;
 found   : Null(null)
 required: Int

注意,不要被Unit值类型在赋值时的障眼法给骗了,以为null可以被赋给Unit

scala> val u:Unit = null
u: Unit = ()

实际上把任何表达式结果不是Unit类型的表达式赋给Unit类型变量,都被转为 { expr; () },所以上面的等同于{null; ()} 把最终得到的()赋给了u变量。

Null在类型推导时只能被造型为AnyRef分支下的类型,不能造型为AnyVal分支下的类型,不过我们显式的通过asInstanceOf操作却又是可以把null造型为AnyVal类型的:

scala> null.asInstanceOf[Int]
res0: Int = 0

这是因为asInstanceOf操作导致了装箱拆箱的行为,在值类型的一些细节里有提到过;

val i = null.asInstanceOf[Int]

// 类似于java里的
int i = (int)((Integer)null);

先装箱Int为引用类型,null被造型成了引用类型的Int(java.lang.Integer),然后又做了一次拆箱,把一个为null的Integer类型变量造型成Int值类型,但在拆箱这一点处理上,体现了scala与java的不同

// java里,编译通过,运行失败,空指针异常
int i = (int)((Integer)null);

// scala里,把值为null的Integer拆箱为值类型Int是ok的,得到Int的默认值0
val i = null.asInstanceOf[java.lang.Integer].asInstanceOf[Int]

在java里基本类型(primitive type) 与引用类型是有明确差异的,虽然提供了自动装箱拆箱的便捷,但在类型上两者是不统一的;而scala里修正这一点,Int类型不再区分int/Integer,类型一致,所以值为null的Integer在通过asInstanceOf[Int]时被当作一个未初始化的Int对待,返回了一个默认值Int(注:asInstanceOf不改变原值,返回一个新值)

这一点对自定义的值类型也一样

scala> class A(val i:Int) extends AnyVal
defined class A

scala> null.asInstanceOf[A]
res18: A = A@0

Nothing类型的特殊之处在于它没有对应的值,这个类型存在的意义或许只是为了类型推导:

scala> def foo = throw new RuntimeException
foo: Nothing

因为scala里每个表达式都有结果,也包括throw语句,它的返回类型是Nothing,而实际运行中会导致线程终止,所以只是编译时用于类型推导

scala> def foo(i:Int) = if (i==100) "OK" else throw new RuntimeException
foo: (i: Int)String

上面if分支返回String类型,而else分支是Nothing,返回值类型是String与Nothing在类型树上的最小公共父类型,因为Nothing是String的子类型,所以直接返回了 String类型。

另外Nothing可用在泛型情况下:

scala> val l:List[Int] = List[Nothing]()
l: List[Int] = List()

因为List[+A]定义是协变的,所以List[Nothing]是List[Int]的子类,但List[Null]不是List[Int]的子类

scala> val l:List[Int] = List[Null]()
<console>:7: error: type mismatch;
 found   : List[Null]
 required: List[Int]

Null与Nothing,造型问题》上有2个想法

发表评论

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