Kotlin Can';t具体化传递给forEach的可暂停块
给一些Kotlin Can';t具体化传递给forEach的可暂停块,kotlin,coroutine,kotlinx.coroutines,Kotlin,Coroutine,Kotlinx.coroutines,给一些 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 //
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)
}
就静态类型系统而言,这里的情况是什么?当前的情况看起来像是一种快速攻击,其中包含suspend fun
调用的内联块仍然被推断为非挂起类型签名
这是一个设计在最终确定之前需要改进的领域吗?暂停功能类型和正常功能类型不是彼此的子类型,因此不能分配或传递给一个功能来代替彼此:
val f: () -> Unit = { }
val g: suspend () -> Unit = f // Type mismatch
val f: suspend () -> Unit = { }
val g: () -> Unit = f // Type mismatch
这就是为什么不能将suspend(Int)->单元
传递给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
}
我已经提出了一个关于支持
(1..10).forEach(action)
的问题:您说“这就是为什么挂起(Int)->单元
不能传递给forEach
”,但是(1..10).forEach{action()}
中的内联lambda类型是什么?IDE说它是(Int)->Unit
,关于从“内联lambda块”调用suspend funs有特殊规则吗?这在类型系统中是如何捕获的?为了更清楚地强调我的担忧,(1..10).toList().stream().forEach{a()}
即使它也是一个文本块,并且具有(几乎)相同的类型签名,也不起作用。我知道所有这些都挂在inline fun
修饰符上,但是当前的规则似乎非常复杂,没有明确的形式化。关于从inline lambda调用挂起函数的特殊规则,您是对的:正如我所说的,挂起函数可以从另一个挂起函数/lambda中的内联函数文本内部调用,在这种情况下,文本本身是否被类型化为suspend
函数并不重要。事实上,该规则的概念与函数文本的类型不同,但在我看来,它非常合理:您可以在另一个suspend函数/lambda中调用一个suspend函数,并且只允许在内联函数文本中进行此类调用可确保调用在外部函数执行期间发生(这反过来又是编译器将挂起函数体正确转换为状态机所必需的),因此调用挂起函数的代码不会泄漏到外部挂起函数之外的某个地方。是,这种行为是合理的,我对其背后的所有理由都很熟悉。我担心的是,我的问题是关于类型系统中这些规则的形式化,而目前还不存在。特别令人困惑的是,suspend
是用类型表示的,而inline
不是,因此需要额外的规则来解释什么是允许的,什么是不允许的。我发布的只是一个例子,当你依赖IDE没有清晰呈现给你的波浪形规则时,你会发现设计漏洞。