5.3 关于Nothing
的更多情况
我们了解到了需要Any
的缘由,但是Nothing
的目的何在呢?
Scala的类型推演辛勤地工作,确定表达式和函数的类型。如果推演出的类型过于宽泛,则无助于类型校验。与此同时,如果一个分支返回Int
,另一个分支抛出异常,那么该如何推演表达式或函数的类型呢?在这种情况下,将类型推演为Int
会比通用的Any
更有用。也就是说,抛出异常的分支必须推演为返回Int
或是Int
的子类型,以得到兼容。不过,任何地方都可能抛出异常,并非所有的表达式都可以推演为Int
。Scala用Nothing
类型——所有类型的子类——帮助类型推演更平滑的工作。既然它是任何类型的子类,它就可以替换任何东西。Nothing
是抽象的,因此,在运行时,它的实例并不会真实存在。它纯粹就是类型推演的帮手。
我们用一个例子进一步探索这一点。下面是一个抛出异常的方法,我们看一下Scala如何推演类型:
def madMethod() = { throw new IllegalArgumentException() }
println(getClass().getDeclaredMethod("madMethod", null).
getReturnType().getName())
方法madMethod()
只是抛出一个异常。使用反射可以查询到这个方法的返回类型,结果如下⑤:
⑤在Scala中,
$
符号指向一个内部表示。
scala.runtime.Nothing$
根据抛出异常的表达式,Scala推演出返回类型为Nothing
。Scala的Nothing
实际上有些非同寻常——它是所有其他类型的子类型。这样一来,Nothing
就可以替换Scala里的任何东西。