两个this 一起用?Kotlin 的成员扩展函数和 implicit receiver

发布网友 发布时间:2024-10-24 12:56

我来回答

1个回答

热心网友 时间:2024-10-27 06:40

大家好,我是扔物线朱凯。

今天咱说说 Kotlin 的 implicit receiver。这是一个我们写 Kotlin 经常会用的东西,虽然你可能都没听过这个词,但你一定用过它。Kotlin 的很多高级功能,都利用到了这个概念——比如协程,协程是重度依赖它的,非常重。所以,弄明白它是个什么、怎么用、怎么去发挥它最大的价值,对我们的能力提升是非常有帮助的。

定义:其实隐式的接收器就是this。所谓的接收,其实指的就是接收调用,或者说接受调用。接受函数的调用啊,接受属性的访问啊。比如这个user.name:

左边的user 就是它的 receiver。谁的 receiver?对于 name 的访问的 receiver。

而隐式的 receiver,指的就是不用写也自动存在的 receiver。也就是如果我把这个user. 给删了,它依然能取到某个 User 对象的 name:

那么这个隐式地被应用的User 对象,就是对这个 name 的访问的 implicit receiver,隐式的 receiver。

嵌套的 implicit receiver 在 Kotlin 里是可以嵌套的,比如在 Java 里我们可以这么写:

我在这个内部类的里面,想访问内部类和外部类的成员都是可以的,是吧:

这个innerInt 是 InnerClass 里的,所以它等价于加上 this 的写法:

而下面的outerInt 属于外面的 OuterClass,但为了避免歧义,Java 不允许我们直接写 this:

而需要显式地加上OuterClass 的前缀:

而上面的innerInt 如果展开,前缀是 InnerClass:

也就是说,在内部类的里面,我是有内部类和外部类的双重this 的。对吧?

另外,对于它们同名的成员变量或者方法,如果我也省略掉this:

拿到的就是内部类的成员。如果想拿外部类的,就必须把this 写完整:

Kotlin 增加的 implicit receiver 嵌套:通过函数的 receiver 指定

然后,Kotlin 对于这种嵌套,又新增了一类场景——咱刚才看的是通过内部类来嵌套是吧?Kotlin 让我们还可以直接通过函数来嵌套新的this。比如你有一个在类型内部声明的扩展函数:

——这种函数叫 member extension function,成员扩展函数,其实就是字面意思:它既是成员函数又是扩展函数,对吧?

这种「成员扩展函数」有一个问题:一方面,因为它是Int 的扩展函数,所以你需要对 Int 类型的对象才能调用它;但同时,它也是 IntMultiplier 的成员函数,所以你还要求你对 IntMultiplier 对象调用它:

也就是说,这里需要的是个双重 receiver:既要这个直接的Int,又要那个外部的 IntMultiplier,缺一不可。——那我到底对谁调用?

Kotlin 提供的解法是,你专门创建一个函数,并给它设置一个函数类型的参数:

函数不用做什么特别的事,关键是执行一下它的那个函数类型的参数:

另外,你要给这个函数类型的参数,设置一个 receiver 的类型:

这么一指定,就把参数的函数体内部——注意,是这个block 的函数体,不是外部函数本身的函数体——在它内部强行安插了一个隐式的 receiver。换句话说,我在调用这个外部函数的时候,它的函数类型的参数的大括号里就有一个 IntMultiplier 类型的 this 了:

通过这种写法,我们就可以任意地往代码里插入我们指定的 implicit receiver,或者说指定的this,去应对「多个 this」的需求场景了。

协程里的应用

Kotlin 的官方代码,以及很多第三方库,都重度地依赖这个叫做 implicit receiver 的东西。虽然我们可以说「它不就是this 嘛」,但关键是,它给我们带来了很大的方便,怎么叫其实是次要的。随便举个例子,我们知道协程的启动是一定要用 CoroutineScope 才行的:

但是为什么在协程的内部再启动新的协程,就不用写CoroutineScope 了?

因为它有一个隐式的CoroutineScope 作为 this 被提供了:

总结

其他很多官方源码以及第三方库,都有类似的应用,而我们自己也可以在代码里用这样的写法去安插新的this 层级,或者说——安插 implicit receiver,隐式的 receiver。看起来好像很复杂,但当你明白它的这些本质逻辑,写起来就很简单了。

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com