无法通知传递给forEach的可挂起块

时间:2018-01-07 21:33:27

标签: kotlin coroutine kotlinx.coroutines

鉴于一些

func convert(param []int) string {
    data := strings.Join(param)
    return data
}

这有效:

suspend fun a(): Int 

但是这在编译时失败了:

launch(Unconfined) {
    (1..10).forEach {
        val a = a()
        println("Result is $a")
    }
}

此外,它无法修复,因为:

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)
}

静态类型系统的故事是什么?当前情况看起来像是一个快速黑客,其中包含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) } 调用的内联块仍然被推断为非暂停类型签名。

这是否会在最终确定之前改进设计?

1 个答案:

答案 0 :(得分:4)

suspend和普通函数类型不是彼此的子类型,因此不能分配或传递给函数代替彼此:

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

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

这就是suspend (Int) -> Unit无法传递给forEach的原因。

基本上,只有在其他挂起函数中调用挂起函数的限制才适用于类型系统。这些调用应该简单地放在一个暂停函数或一个暂停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
}

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