Kotlin并行协程用select取首个非空值报return不允许错误如何解决
报错原因
你遇到的'return' is not allowed here错误是因为Kotlin不允许在普通lambda表达式中使用非局部返回,onAwait的回调lambda要求你必须返回一个值作为当前select分支的结果,不能直接通过return跳出整个select逻辑。
解决方案
你可以通过循环select的方式实现需求:每次执行select时如果拿到的结果是空,就把对应的已完成的空结果协程从待选列表移除,再次对剩下的未完成协程执行select,直到拿到第一个非空结果为止,拿到结果后可以主动取消所有剩余协程释放资源。
完整实现示例:
import kotlinx.coroutines.* import kotlinx.coroutines.selects.* import java.util.* fun CoroutineScope.asyncString(time: Int, content: String? = null) = async { delay(time.toLong()) content } fun CoroutineScope.asyncStringsList(): List<Deferred<String?>> { val random = Random(3) // 模拟部分协程返回空,部分返回非空 return List(12) { index -> asyncString(random.nextInt(1000), if (index == 5) "第一个非空结果" else null) } } fun main() = runBlocking<Unit> { val list = asyncStringsList() val remainingTasks = list.toMutableList() var result: String? = null while (result == null && remainingTasks.isNotEmpty()) { result = select { remainingTasks.forEach { deferred -> deferred.onAwait { answer -> answer } } } // 把已经返回空结果的任务从待选列表移除 if (result == null) { remainingTasks.removeAll { it.isCompleted } } } // 拿到结果后取消所有剩余未完成的协程 remainingTasks.forEach { it.cancel() } println("最终结果:$result") }
补充说明:
- 示例中将Deferred的泛型改成了
String?适配可能为空的返回值 - 如果所有协程都返回空,最终result会是null,你可以根据业务需求补充兜底逻辑
- 取消剩余协程的步骤可选,如果你不需要后续协程的执行结果,建议加上减少不必要的资源消耗
内容的提问来源于stack exchange,提问作者ASDEV
相关产品推荐
相关产品推荐

