Kotlin Type Hierarchy
Kotlin类型层级一览(翻译原文)
Kotlin有很多关于语言的文档和教程指南。但是没有看关于类型层级的相关描述。
了解之后,我发现非常的简洁。
Kotlin类型层级要学习的规则非常少,这些规则保持一致性和可预见性。有了这些规则,Kotlin可以提供有用的,用户可扩展的语言特性,例如:null安全,多态性和无法执行代码检测;不需要在IDE和编译阶段做特殊处理和额外的操作。
从顶层开始
所有Kotlin对象的类型都组织在“子类型/父类型”的关系层级中。
最顶层一级是抽象类”Any”,例如:String和Int都是Any的子类型
class Fruit(val ripeness: Double) |
abstract class Fruit(val ripeness: Double) |
interface ICanGoInASalad |
Kotlin类型检查强制子类型/父类型之间的关系
例如:可以使用父类型变量保存一个子类型
var f: Fruit = Banana(bendiness=0.5) |
但是不能够使用子类型变量保存父类型
val b = Banana(bendiness=0.5) |
Nullable可以为空的类型
和Java不同Kotlin区分“非空”和“空”类型。上面提到的都是非空类型。Kotlin不允许把null赋值给“非空类型”。这样可以保证你在解引用一个“非空类型”的时候,永远也不会抛出NullPointerException异常
类型检查会拒绝把null或者“空类型”赋值给“非空类型”
例如:
var s : String = null |
如果想要一个“空类型”,可以使用后缀“?“。例如:String?就是一个可以为空的字符串类型。
var s : String? = null |
类型检查会保证你在使用”空类型“之前一定会检查是否为空。参见
Null Safety section of the Kotlin language reference
”非空类型“和”空类型“是可以继承的。例如:String是Any的子类型,String?是Any?的子类型,Banana是Fruit子类,Banana?是Fruit?子类。
就像Any是所有非空类型的父类一样,Any?也是所有空类型的父类。
同时Any?也是Any的父类,Any?是kotlin类型层级中最顶端的。
一个非空类型是它对应的空类型的子类。例如:String是Any的子类,同时也是String?的子类。
大多数情况下不需要显示指定返回值,编译器会认为返回Unit,否则编译器会推导返回类型。
fun example() { |
Unit并不特殊,它和其他类型一样也是Any的子类型,也可以是空类型。
Nothing
在cotlin类型层级中最底层的是Nothing。
就像他的名字一样,Nothing是一个没有实例的类型。Nothing表达式不会返回任何值。
注意Unit和Nothing的区别。对一个Unit表达式求值的时候返回一个单例模式的值Unit。对Nothing表达式求值永远都不会返回。
也就是说任何在Nothing类型的表达式后面的代码是执行不到的。编译器会警告这类无法执行的代码。
什么样的表达式会得出Nothing呢?那就是执行流程控制的时候。
例如:
使用throw关键字中断一个表达式计算,从函数中抛出异常。抛异常就是一个Nothing类型的表达式。
通过把Nothing作为所有其他类型的子类型,类型系统允许任何一个表达式可以在计算的时候失败(注:原文如下,感觉不理解这段话,翻译的可能有问题。the type system allows any expression in the program to actually fail to calculate a value.)。这是对真实世界任何可能性的建模。例如JVM在计算表达式的时候内存溢出,或者有人拔掉了计算机的电源线。
这也意味着我们可以在任何表达式中抛出异常。
fun formatCell(value: Double): String = |
一个无限循环的函数或者终止当前进程的返回类型都是Nothing。例如Kotlin标准库声明的exitProcess函数如下:
fun exitProcess(status: Int): Nothing |
如果你自己写的函数返回了Nothing,编译器会检查调用你函数之后是否有无法执行的代码,就像内置的流程控制语句一样。
inline fun forever(action: ()->Unit): Nothing { |
就像安全null一样,无法执行代码的检查也不是像Java一样通过额外操作或者在IDE和编译器中做特殊处理做到的,而是类型系统的一个功能。
Nullable Nothing?
Nothing和其他类型一样,可以为空,通过Nothing?表示。Nothing?只有一个值null,事实上Nothing?就是null类型.
Nothing?是所有空类型的最终的子类型,这使得null可以赋值给任何空类型。
我希望通过这篇文章演示Kotlin拥有一个简单并且保持一致性的类型系统。
只有很少的规则需要学习:
1 一个最顶端的Any?和最底端的Nothing相关的子类/父类层级关系
2 空类型和非空类型之间的子类关系
就这些,没有特殊情况。
那些有用的语言特性例如安全null,面向对象的多态,无法执行代码的检测,都是这些简单,可预见的规则的结果。