如何在 Kotlin 中创建具有多个接收器的扩展功能?

How to create an extension function with multiple receivers in Kotlin?

我希望我的扩展函数有几个接收器。例如,我希望函数 handle 能够调用 CoroutineScopeIterable 实例的方法:

fun handle() {
    // I want to call CoroutineScope.launch() and Iterable.map() functions here
    map {
        launch { /* ... */ }
    }
}

我认为这可能有效:

fun <T> (Iterable<T>, CoroutineScope).handle() {}

但是它给我一个错误:

Function declaration must have a name

我知道我可以创建带有参数的函数,但是

是否可以为单个函数设置多个接收器?如何在没有参数的情况下实现?

据我所知,对于我们无法控制的类型,目前这是不可能的。有计划添加这样的功能,在KEEP-259.

下处理

我不知道计划的路线图是什么,也不知道什么时候可以添加,但我希望我们今年至少能看到一些预览。

这是一个非常狭窄的案例,但如果您的用例是您有一个高阶函数,您希望 lambda 中的代码具有多个接收器,并且如果您想要组合的类型是接口,您可以创建一个 class 将接口包装为委托。在传递给以下函数的 lambda 中,您可以同时调用 Iterable 和 CoroutineScope 函数。

class CoroutineScopeAndIterable<T>(
    private val coroutineScope: CoroutineScope,
    private val iterable: Iterable<T>
): CoroutineScope by coroutineScope, Iterable<T> by iterable

suspend fun <T> CoroutineScope.runSomething(
    iterable: Iterable<T>, 
    block: suspend CoroutineScopeAndIterable<T>.() -> Unit
) {
    CoroutineScopeAndIterable(this, iterable).block()
}

您可以使用以下解决方法:

val <T> Iterable<T>.handle: CoroutineScope.() -> Unit get() = {
  map {
    launch {  }
  }
}

在 Kotlin 版本 1.6.20 中有一个名为 Context receivers 的新功能。这是上下文接收器的第一个原型。此功能允许通过将上下文接收器添加到它们的声明来创建函数、属性和 类 context-dependent。有一个新的语法。在函数声明之前,我们可以指定调用此函数所需的上下文类型列表。上下文声明执行以下操作:

  • 它要求所有声明的上下文接收器都作为隐式接收器出现在调用者的范围内。
  • 它将声明的上下文接收器带入隐式接收器的主体范围。

上下文接收器的解决方案如下所示:

context(CoroutineScope)
fun <T> Iterable<T>.handle() {
    map {
        launch { /* ... */ }
    }
}

someCoroutineScope.launch {
    val students = listOf(...)
    students.handle()
}

context(CoroutineScope)中我们可以声明多个类型,例如context(CoroutineScope, LogInterface).

由于上下文接收器功能是一个原型,要启用它,请在应用的 build.gradle 文件中添加 -Xcontext-receivers 编译器选项:

apply plugin: 'kotlin-android'
android {
    //...
    kotlinOptions {
        jvmTarget = "11"
        freeCompilerArgs += [
                "-Xcontext-receivers"
        ]
    }
}