无法验证传递给forEach的可暂停块

Mar*_*nik 4 coroutine kotlin kotlinx.coroutines

给一些

suspend fun a(): Int 
Run Code Online (Sandbox Code Playgroud)

这有效:

launch(Unconfined) {
    (1..10).forEach {
        val a = a()
        println("Result is $a")
    }
}
Run Code Online (Sandbox Code Playgroud)

但这在编译时失败:

val action: (Int) -> Unit = {
    // Suspend function should be called only from a coroutine
    // or another suspend function:
    val a = a()
    println("Result is $a")
}
launch(Unconfined) {
    (1..10).forEach(action)
}
Run Code Online (Sandbox Code Playgroud)

此外,它不可修复,因为:

val action: suspend (Int) -> Unit = {
    val a = a()
    println("Result is $a")
}
launch(Unconfined) {
    // suspend (Int) -> Unit cannot be applied to (T) -> Unit
    (1..10).forEach(action)
}
Run Code Online (Sandbox Code Playgroud)

关于静态类型系统,这里的故事是什么?当前的情况看起来像是快速黑客,其中包含suspend fun调用的内联块仍被推断为非挂起类型签名。

这是在最终确定设计之前将对其进行改进的领域吗?

hot*_*key 5

suspend和正常的功能类型不是彼此的亚型,因此不能代替彼此的被分配或传递给函数:

val f: () -> Unit = { }
val g: suspend () -> Unit = f // Type mismatch

val f: suspend () -> Unit = { }
val g: () -> Unit = f // Type mismatch
Run Code Online (Sandbox Code Playgroud)

这就是为什么a suspend (Int) -> Unit不能传递给的原因forEach

基本上,不管类型系统如何,仅在其他暂挂函数中调用暂挂函数的限制都是有效的。这样的调用应该简单地放在一个suspend函数或一个suspend lambda中,或者内联到一个函数中。因此,这也应该起作用:

val action: suspend (Int) -> Unit = {
    val a = a()
    println("Result is $a")
}
launch(Unconfined) {
    (1..10).forEach { action() } // The call is inlined into a suspend lambda
}
Run Code Online (Sandbox Code Playgroud)

我也提出了有关支持的问题(1..10).forEach(action)KT-22186