青岛网站建设 推荐青岛博采网络,域名备案是永久的吗,高中信息技术网站建设,网站如何加入广告联盟1.Nothing的本质
Nothing 的源码很简单#xff1a;
public class Nothing private constructor()可以看到它是个class#xff0c;但它的构造函数是 private 的#xff0c;这就导致我们没法创建它的实例#xff0c;并且在源码里 Kotlin 也没有帮我们创建它的实例。
基于这…1.Nothing的本质
Nothing 的源码很简单
public class Nothing private constructor()可以看到它是个class但它的构造函数是 private 的这就导致我们没法创建它的实例并且在源码里 Kotlin 也没有帮我们创建它的实例。
基于这样的前提当我们写出这个函数声明的时候
fun nothing(): Nothing {}我们不可能找到一个合适的值来返回因为压根找不到Nothing的实例
2.作用一作为函数「永不返回」的提示
上面的例子看起来是个悖论但它其实就是 Nothing 存在的意义它找不到任何可用的值所以以Nothing为返回值类型的函数一定是个不会返回的函数。
比如它可以总是抛异常
fun nothing() : Nothing {throw RuntimeException(Nothing!)
}这个写法并没有返回任何结果而是抛异常了所以是合法的。
注意抛异常是可以忽略返回值而且这不是 Nothing 的特性在Java和Kotlin中都是如此
//Java
public String getName() {throw new NullPointerException(不能为空);
}//Kotlin
fun getName() : String {throw NullPointerException(不能为空)
}上面这个getName()看起来有点奇怪为什么在一个函数中就只是抛出异常呢但它的写法本身是完全合法的。如果把函数的名字改一下再加个注释
/**当遇到姓名为空的时候请调用这个函数来抛异常
*/
fun throwOnNameNull() : String {throw NullPointerException(姓名不能为空)
}这就很合理了吧不干别的就只是抛异常。这是一种很常用的工具函数的写法包括 Kotlin 和 Compose 的官方源码里也有这种东西。
那么我们继续来看它的返回值类型我都不返回了就没必要还写 String 了吧那写什么可以把它改成 Unit
fun throwOnNameNull() : Unit {throw NullPointerException(姓名不能为空)
}甚至可以把它改成不写返回值。但这里不写返回值实际上返回类型是UnitKotlin会自动帮我们加上可以看这篇文章解析Kotlin中的Unit【笔记摘要】
fun throwOnNameNull() : Unit {throw NullPointerException(姓名不能为空)
}fun throwOnNameNull() {throw NullPointerException(姓名不能为空)
}不过Kotlin 又进了一步提供了一个额外的选项你还可以把它改成 Nothing
/**当任何变量为空的时候请统一调用这个函数来抛异常
*/
fun throwOnNameNull() : Nothing {throw NullPointerException(姓名不能为空)
}虽然我找不到 Nothing 的实例但是这个函数本来就是永远抛异常的找不到实例也没关系。
这么写的价值就在于Nothing 这个返回值类型能够给使用它的开发者一个明确的提示这是个永远不会返回的函数。这种提示本身就会给开发提供一些方便它能很好地避免函数的调用者对函数的误解而导致的一些问题。
Kotlin 的源码、Compose 的源码里都有不少这样的实践比如 Compose 的 noLocalProviderFor() 函数
private fun noLocalProvidedFor(name: String): Nothing {error(CompositionLocal $name not present)
}拓展其实 Nothing 的永不返回特性除了抛异常之外还有一种场景就是无限循环
fun foreverRepeat(): Nothing {while (true) {...}
}不过一般很少有人这么去用大部分都是用在抛异常的场景
3.作用二作为泛型对象的临时空白填充
另外 Nothing 除了「没有可用的实例」之外还有个特性它是所有类型共同的子类型。
不过这个特性又有什么作用呢它就能让你对于任何变量的赋值都可以在等号右边写一个 Nothing
val nothing: Nothing ???
var apple: Apple nothing这儿其实有个问题前面刚说了 Nothing 不会有任何的实例对吧那么这个右边就算能填 Nothing 类型的对象可是这个对象我用谁啊谁也没法用。
但是如果不直接用 Nothing而是把它作为泛型类型的实例化参数。一个元素类型为Nothing 的 List将会导致我无法找到任何的元素实例来填充进去但是这个 emptyList 本身是可以被创建的
val emptyList: ListNothing listOf()
var apples: ListApple emptyList结合上我们刚说的「Nothing 是所有类型的子类型」这个特性我们是不是可以把这个空的 List 赋值给任何的 List 变量这里实际上用到了协变的知识
val emptyList: ListNothing listOf()
var apples: ListApple emptyList
var users: ListUser emptyList
var phones: ListPhone emptyList
var images: ListImage emptyList这样是不是就提供了一个通用的空 List 出来让这一个对象可以用于所有 List 的初始化。有什么好处既省事又省内存这就是好处。
这种用法不只可以用在 ListSet 和 Map 也都没问题
val emptySet: SetNothing setOf()
var apples: SetApple emptySet
var users: SetUser emptySet
var phones: SetPhone emptySet
var images: SetImage emptySetval emptyMap: MapString, Nothing emptyMap()
var apples: MapString, Apple emptyMap
var users: MapString, User emptyMap
var phones: MapString, Phone emptyMap
var images: MapString, Image emptyMap而且也不限于集合类型只要是泛型都可以你自定义的也行
val emptyProducer: ProducerNothing Producer()
var appleProducer: ProducerApple emptyProducer
var userProducer: ProducerUser emptyProducer
var phoneProducer: ProducerPhone emptyProducer
var imageProducer: ProducerImage emptyProducer它的核心在于你利用 Nothing 可以创建出一个通用的「空白」对象它什么实质内容也没有什么实质工作也做不了但可以用来作为泛型变量的一个通用的空白占位值。
4.作用三语法的完整化
另外Nothing 的「是所有类型的子类型」这个特点还帮助了 Kotlin 语法的完整化。
在 Kotlin 的下层逻辑里throw 这个关键字是有返回值的它的返回值类型就是 Nothing。虽然说由于抛异常这件事已经跳出了程序的正常逻辑所以 throw 返回不返回值、返回值类型是不是 Nothing 对于它本身都不重要但它让这种写法成为了合法的
val nothing: Nothing throw RuntimeException(抛异常)并且因为 Nothing 是所有类型的子类型所以我们这么写也行
val nothing: String throw RuntimeException(抛异常)看起来没用是吧如果我再把它改改就有用了
var _name: String? null
val name: String _name ?: throw NullPointerException(_name 在运行时不能为空)throw 的返回值是 Nothing我们就可以把它写在等号的右边在语法层面假装成一个值来使用但其实目的是在例外情况时抛异常。虽然 throw 不会真正地返回但这让语法层面变得完全说得通了这也是 Nothing 的价值所在。
除了 throw 之外单独的 return 也是被规定为返回 Nothing 的一个关键字所以我也可以这么写
fun sayMyName(first: String, second: String) {val name if (first Walter second White) {Heisenberg} else {return // 语法层面的返回值类型为 Nothing赋值给 name}println(name)
}单独 return 语法层面的返回值类型为 Nothing可以赋值给 name让代码从语法层面就能得到解释从而帮助了 Kotlin 语法的完整化。 参考文章 这玩意真的有用吗对是的Kotlin 的 Nothing 详解