从标签 Kotlin 的内部嵌套协程返回
Returning from inner nested coroutine by label Kotlin
用例:我有很多操作想从主线程异步发生,但也希望彼此并行发生。
val scope = CoroutineScope(Dispatchers.IO)
val items = // List of items to do something.
scope.launch {
items.forEach { item ->
scope.launch {
if (itemFailsValidation(item)) {
// Here I want to skip this item but continue the forEach loop.
return@launch // "There is more than one label with such a name in this" scope"
}
doSomethingThatMightTakeABit(item)
}
}
}
如果我尝试添加标签,例如 inner@scope.launch
,编辑器会说“标签是多余的,因为它不能在 ''break''、''continue'' 中引用, 或 ''return'' 表达式
有谁知道这样做的好方法吗?
您可以使用 name@
关键字更改 lambda 的名称。
示例:
scope.launch outerCoroutine@ {
items.forEach { item ->
scope.launch {
if (itemFailsValidation(item)) {
return@outerCoroutine
}
doSomethingThatMightTakeABit(item)
}
}
}
此功能没有正确记录,但一些文档如 This expressions 中有演示用法,标准库中定义的一些函数使用它。
编辑: 这实际上记录在 Return and Jumps。
如果我们需要从 lambda 表达式 return,我们必须 label it and qualify the return。对于你的情况,从内部协程到 return:
scope.launch {
items.forEach { item ->
scope.launch innerScope@ {
if (itemFailsValidation(item)) {
return@innerScope
}
doSomethingThatMightTakeABit(item)
}
}
}
但我们可以简化您的案例并在不使用标签的情况下重写代码:
scope.launch {
items.forEach { item ->
if (!itemFailsValidation(item)) {
scope.launch { doSomethingThatMightTakeABit(item) }
}
}
}
// OR
items.forEach { item ->
if (!itemFailsValidation(item)) {
scope.launch { doSomethingThatMightTakeABit(item) }
}
}
如果您想等待所有协程完成并在 UI 线程上执行某些操作:
scope.launch(Dispatchers.Main) {
processItemsInBackground()
// update UI after processing is finished
}
suspend fun processItemsInBackground() = withContext(Dispatchers.IO) {
// withContext waits for all children coroutines
items.forEach { item ->
if (!itemFailsValidation(item)) {
launch { doSomethingThatMightTakeABit(item) }
}
}
}
用例:我有很多操作想从主线程异步发生,但也希望彼此并行发生。
val scope = CoroutineScope(Dispatchers.IO)
val items = // List of items to do something.
scope.launch {
items.forEach { item ->
scope.launch {
if (itemFailsValidation(item)) {
// Here I want to skip this item but continue the forEach loop.
return@launch // "There is more than one label with such a name in this" scope"
}
doSomethingThatMightTakeABit(item)
}
}
}
如果我尝试添加标签,例如 inner@scope.launch
,编辑器会说“标签是多余的,因为它不能在 ''break''、''continue'' 中引用, 或 ''return'' 表达式
有谁知道这样做的好方法吗?
您可以使用 name@
关键字更改 lambda 的名称。
示例:
scope.launch outerCoroutine@ {
items.forEach { item ->
scope.launch {
if (itemFailsValidation(item)) {
return@outerCoroutine
}
doSomethingThatMightTakeABit(item)
}
}
}
此功能没有正确记录,但一些文档如 This expressions 中有演示用法,标准库中定义的一些函数使用它。
编辑: 这实际上记录在 Return and Jumps。
如果我们需要从 lambda 表达式 return,我们必须 label it and qualify the return。对于你的情况,从内部协程到 return:
scope.launch {
items.forEach { item ->
scope.launch innerScope@ {
if (itemFailsValidation(item)) {
return@innerScope
}
doSomethingThatMightTakeABit(item)
}
}
}
但我们可以简化您的案例并在不使用标签的情况下重写代码:
scope.launch {
items.forEach { item ->
if (!itemFailsValidation(item)) {
scope.launch { doSomethingThatMightTakeABit(item) }
}
}
}
// OR
items.forEach { item ->
if (!itemFailsValidation(item)) {
scope.launch { doSomethingThatMightTakeABit(item) }
}
}
如果您想等待所有协程完成并在 UI 线程上执行某些操作:
scope.launch(Dispatchers.Main) {
processItemsInBackground()
// update UI after processing is finished
}
suspend fun processItemsInBackground() = withContext(Dispatchers.IO) {
// withContext waits for all children coroutines
items.forEach { item ->
if (!itemFailsValidation(item)) {
launch { doSomethingThatMightTakeABit(item) }
}
}
}