8

我有一个Job实例列表,我想在启动后的某个时候取消这些实例。这看起来如下:

val jobs = arrayListOf<Job>()
//launch and add jobs...
jobs.forEach { it.cancelAndJoin() } // cancels the jobs and waits for completion

不幸的是,这里不可能使用方法参考。原因:cancelAndJoin是一个suspend函数,正如编译器抱怨的那样:

jobs.forEach (Job::cancelAndJoin) 

“错误:(30, 24) Kotlin:不支持 [对挂起函数的可调用引用]”

为什么这不起作用?

4

2 回答 2

10

UPD:这已经在 Kotlin 1.3.x 中实现。对挂起函数进行可调用引用会为您提供KSuspendFunctionN( N= 0, 1, ...) 的实例。此类型将其invoke运算符定义为挂起函数,因此您可以像直接调用一样调用挂起协程的可调用引用。


基本上,支持这一点需要额外的语言设计部分,而不是简单地与协程捆绑在一起。

为什么它不是微不足道的?因为当您获取普通函数的可调用引用时,例如String::reversed,您会得到类似KFunction1<String, String>. 如果你可以对一个suspend函数做同样的事情,你希望得到什么?

如果相同KFunctionN<...>,那么有一个明显的问题是,您可以将其传递到期望普通函数的位置并调用它,这违反了suspend函数只能在协程内部调用的规则(编译器在其中转换其调用站点)。

所以,它应该是更具体的东西。(我目前只是推测,没有任何实际设计尝试的想法)例如,它可能是 a SuspendKFunctionN<...>,它invoke(...)是一个挂起函数,或者它可能(不太可能)是一个特殊符号,仅用于传递函数引用,其中asuspend (T) -> R是意料之中的,但无论如何,这样的功能需要彻底的设计才能适应未来。

于 2017-11-10T21:51:03.360 回答
2

Kotlin 标准库中目前缺少这些助手,但您可以实现自己的。

例如:

suspend fun <T> Iterable<T>.forEachAsync(action: suspend (T) -> Unit): Unit {
    val list = this.map { e ->
        async(...) {
            action(e)
        }
    }
    list.forEach { it.await() }
}

但是,现在传递给 async 的上下文取决于您的服务使用的线程模型(即您想要执行多线程还是想要将所有内容保存在单个线程中)。

于 2018-08-01T02:34:22.910 回答