Kotlin中如何在代码块内用val定义变量并外部访问?含代码风格疑问
问题解答
1. 如何用val变量在代码块外部访问?var不是唯一选项
你当前的代码里,inAppProducts和subsProducts定义在launch的lambda内部,外部根本访问不到;就算用var声明在外部,runBlocking结束时两个launch的任务也大概率没执行完,变量会处于未初始化状态,直接返回必出问题。
正确的做法是用async替代launch,async会返回Deferred对象,通过await()就能获取任务执行结果,完全可以用val在外部接收:
suspend fun getProducts(): List<Product> = coroutineScope { val inAppProductsDeferred = async(Dispatchers.IO) { queryProductDetails(...) } val subsProductsDeferred = async(Dispatchers.IO) { queryProductDetails(...) } val inAppProducts = inAppProductsDeferred.await() val subsProducts = subsProductsDeferred.await() inAppProducts + subsProducts }
这里用coroutineScope替代runBlocking——因为你在suspend函数里,runBlocking是阻塞线程的工具,违背协程非阻塞的设计初衷。async会并行执行两个查询任务,最后通过await等待两者完成,用val接收结果后合并返回即可。
2. 原编码风格是否良好?
原写法存在多个严重问题,不属于良好编码风格:
- 错误使用
runBlocking:runBlocking是用来把协程桥接到阻塞线程的工具,在已经是suspend的函数里用它,会阻塞调用线程,完全浪费了协程的非阻塞特性,应该用coroutineScope或supervisorScope创建子协程。 launch误用:launch是“fire-and-forget”的启动方式,不会返回任务结果,你没法保证runBlocking结束时两个launch的任务已经完成,此时返回的变量要么未初始化,要么是错误值,必然引发运行时问题。- 作用域违规:你试图访问lambda内部定义的变量,这本身就不符合Kotlin的作用域规则,连编译都通不过。
正确的写法应该像上面的示例那样,用coroutineScope管理子协程,async并行执行任务并获取结果,既保证非阻塞性,又能正确拿到并行任务的结果。
内容的提问来源于stack exchange,提问作者Plasty Grove
相关产品推荐
相关产品推荐

