Kotlin 类型系统原来如此简单

在学习 Kotlin 的过程中,对 Kotlin 的类型系统产生了好奇,Kotlin 是否存在类似于 Java 中 Object 的公共基类?Kotlin 中是否也有类似于 Java 基础类型这样的单独分支?在研究一番过后,博主发现相较于 Java,Kotlin 交出了更为满意的答案,而且出乎意外地简单,只需要遵循简单的规则,便能理解整个类型系统。

Any

Any 等同于 Java 中的 Object 的概念,Any 在注释中这么写到:

The root of the Kotlin class hierarchy. Every Kotlin class has [Any] as a superclass.

我们来简单验证下 Any 是一切的基类。

class Fruit
fun main(args: Array<String>) {
    println(Fruit() is Any)
}

在上面的代码中,我们新建了一个类,然后构造它的实例,看它是否为 Any,答案显而易见地为 true

我们在看一些 kotlin 中的基础类型,也就是 Int、Double、Float、Byte 等等的父类是否也是 Any。

println(3.233F is Any)
println(2 is Any)

答案也是 true 。这里额外地解释下,Kotlin 并没有 Java 中基础类型和封装类型差异化处理,也没有 拆箱装箱 的处理。基础类型就是基础类型,但它们也以 Any 作为父类。

Unit

再来看看 Unit 这个 Kotlin 中的特殊东西。

/**
 * The type with only one value: the `Unit` object. 
 * This type corresponds to the `void` type in Java.
 */
public object Unit {
    override fun toString() = "kotlin.Unit"
}

在 kotlin 中每个函数一定是有返回值的。

这里说明一下概念,也将会在后续的章节里面再次提到。kotlin 为了这个一定有返回值这个概念,做了很多工作,但好处是非常明显的,我们能够以统一的视角来看待 kotlin 的函数。

Unit 这个概念表征着什么都不做,但什么都不做确实也是一种返回值。如果我们不做任何声明,函数的返回值就是 Unit,表明我返回了一个什么都没做的东西。

我们来验证一下,声明一个空函数,然后打印它。(

在 Java 中会编译不过

)

fun justReturn() {
}

fun main(args: Array<String>) {
    print(justReturn())
}

结果输出了 kotlin.Unit ,证明了返回值就是 Unit。

那么这里有一个疑问,就是 Unit 和 Any 什么关系?我们通过 is 关键字来看看。

fun main(args: Array<String>) {
    print(justReturn() is Any)
}

恩恩,Unit 也是 Any 的子类!

Nothing

我们继续延展下 kotlin 中每个函数一定是有返回值的 这个概念。前面我们看的是正常返回的情况,那如果程序发生异常,也会有返回值吗?kotlin 对于这种情况,也是延续了一定有返回值这种概念。这个返回值叫做 - Nothing!

Nothing 意味着不可达,程序实际运行时不会产生任何一个 Nothing 类型对象,啥?!这怎么理解。kotlin 一旦发现返回了 Nothing,会保证后面的代码不再执行。

所以 Nothing 常用于 throw 这样异常退出的情况,这样后续的代码就不会被执行。我们看看 kotlin 中自身的例子。

/**
 * Terminates the currently running process.
 *
 * @param status serves as a status code; by convention,
 * a nonzero status code indicates abnormal termination.
 *
 * @return This method never returns normally.
 */
@kotlin.internal.InlineOnly
public inline fun exitProcess(status: Int): Nothing {
    System.exit(status)
    throw RuntimeException("System.exit returned normally, while it was supposed to halt JVM.")
}

注意啦,我们再看看 Nothing 在类型系统中的位置。Nothing 与 Any 相反,是一切类型的子类!也就是说 Nothing,是 Fruit、是 School、是 Money、也是 Any。Nothing 意味着不可达的状态,每一种类型都包含这种不可达的状态,因而这种状态 Nothing,是这些的子类。

注意上图中 Nothing 所处的位置。

Nullable

kotlin 的一大杀手锏就是这个可空类型,一种类型后面加上?,这种类型就可以为空了。我们来看看引入可空类型过后,类型系统是怎样的。

  1. 首先看看普通类和可空类型之间的关系。
    class Fruit
    fun main(args: Array<String>) {
        print(Fruit() is Fruit?)
    }
    

答案是 true ,这里很好理解,两者之间的区别在于是否可以为空,可以为空的自然而然是基类,不可为空的是可以为空下的一种派生。

  1. Any 是否有可空类型

    kotlin 最让人欣赏的地方在于一个概念贯彻到底。Any 在 kotlin 中也是有可空类型的。感官上 Any? 是 Any 的父类,Any 是不可空类型的父类,所以 Any? 也是不可空类型的父类吗?答案就是这样的,我们来验证下。

class Fruit
fun main(args: Array<String>) {
    print(Fruit() is Any?)
}
  1. Unit 是否有可空类型

    是的,Unit 也有空类型 Unit? 。但这是一个难理解的概念,其本身包含了两个值 Unit 和 null。这是 kotlin 为了延续统一的概念,很少会有场景使用到,但咱们得清楚。

  2. Nothing 是否有可空类型

    Nothing 当然也有可空类型 Nothing? ,其本身有且仅有一个值 null ,也就是说其就是 null。Nothing 本身不可达,不会有任何一个实例,那就只能是 null 了。

我们来验证一下

fun main(args: Array<String>) {
	println(null is Nothing)
	println(null is Nothing?)
	println(null is Any)
	println(null is Any?)
}

分别是 false、true、false 和 true。

总结

这里借用下 natpryce 的图,大家看一下这张图,这就是 kotlin 的类型系统。

咱们只需要理解一下几点,就完全弄明白 kotlin 类型系统。

  1. Any 和 Nothing 分别是所有对象的基类和子类。
  2. 可空类型是不可空类型的父类。

当我们不清楚类型时,对照上面两个概念就能明白。

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章