(译)Kotlin 之 Nothing
Kotlin 中的 Nothing
到底有什么作用?
原文见Kotlin’s Nothing: Its Usefulness in Generics
本文介绍 Kotlin 中 Nothing
类型在泛型中的作用。先来看一个关于链表的具体例子。
这个链表封装了某种类型,不妨称为 T。链表可以是以下任意一种:
- 类型一 -
Node<T>
。它包含两个属性,T
类型的 payload 和LinkedList<T>
类型的 next - 类型二 - 一个空链表
EmptyList
使用 sealed class
用于保证链表要么是类型一要么是类型二。
所以可以写出如下代码:
1 | sealed class LinkedList<out T> { |
如何写空链表有点挑战。考虑到所有的空链表都是一样的,所以空链表由 Kotlin 中的 object
表示。此外,空链表还必须是 LinkedList<T>
的子类。可以尝试如下写法:
1 | sealed class LinkedList<out T> { |
Kotlin 中的 object
不能带类型参数,所以上面代码编译失败。再来尝试去掉空链表的类型参数。
1 | sealed class LinkedList<out T> { |
代码仍然编译失败。第5行代码中的 T
无法解析。必须为这里的 T
规定一个具体的类型。
见文章开头的那张图,T
是 Node.payload
属性的类型。而空链表并不包含任何 Node
。所以正确的代码如下:
1 | sealed class LinkedList<out T> { |
Kotlin 中 Nothing
类型到底是什么?在 Kotlin REPL 中运行 println(Nothing::class.java)
命令输出结果如下:
1 | println(Nothing::class.java) |
Kotlin 的 Nothing
其实就是 Java 中的 Void
。在 Kotlin 中,Nothing
表示缺少类型。
再来看看为什么不能让 Kotlin 中的函数返回 Nothing?
。比如以下代码编译出错:
1 | fun getNothing() = Nothing() // won't compile |
Kotlin 不允许实例化 Nothing
。Nothing
的构造方法是私有的。看看 Java 版本的 getNothing()
:
1 | public class GetVoidExample { |
Java 中 Void
的构造方法也是私有的。Void
同样不能被实例化。我们也不能返回 Void
。所以这样看来 Kotlin 中不能返回 Void
是合理的。
总结一下: Kotlin 的 Nothing
其实就是 Java 中的 Void
。Kotlin 中 Nothing
用于泛型,表示该泛型不包含任何类型信息,即该类型缺失。