如何正确实现此 Kotlin ReceiveChannel 代码

3

我在跟随一个教程,老师使用ProducerJob方法来演示Kotlin协程,但我的IDE显示该方法已过时,应该使用ReceiveChannel代替,但它也提示我应该在协程范围上使用扩展函数,但我好像无法正确实现它。

以下是老师的代码:

fun produceNumbers() : ProducerJob<Int> = produce {

    for (x in 1..5) {
        println("send $x")
        send(x)
    }
    println("Done")

} 

fun main() = runBlocking{
    val channel = produceNumbers()
    channel.consumeEach {
        println(it)
    }
    println("Main done")

}

以下是我的代码:

fun produceNumbers() : ReceiveChannel<Int> = produce {

        for (x in 1..5) {
            println("send $x")
            send(x)
        }
    println("Done")

}

fun main() = runBlocking{
    val channel = produceNumbers()
    channel.consumeEach {
        println(it)
    }
    println("Main done")

}

代码是否编译成功:是 版本号:kotlinx-coroutines-core-0.27.0.eap13


你的代码编译通过了吗?你使用的协程库版本是哪个?你导入了什么?我认为在最近的协程库版本中,如果没有CoroutineScope,你不能像这样调用produce - Joffrey
1
只是补充一下,这是ProducerJob被完全弃用的地方 https://github.com/Kotlin/kotlinx.coroutines/commit/49b97d0a0eb3d9f8b32976677e769ee784fd2a29 - s4p3r_c1n0s
1个回答

3
声明您的函数为CoroutineScope的扩展是有原因的,这是因为您无论如何都需要一个范围来创建协同程序内置函数。在Kotlin协程库的最新版本中,如果没有范围,您将无法调用produce,它不会编译。
将您的函数声明为CoroutineScope的扩展的方式如下:
fun CoroutineScope.produceNumbers() : ReceiveChannel<Int> = produce {
    for (x in 1..5) {
        println("send $x")
        send(x)
    }
    println("Done")
}

如果您没有在CoroutineScope的扩展中使用它,则需要通过其他方式提供范围(例如封闭类的字段或方法参数),或者使用GlobalScope,但这两种方式都不推荐。上面的基于扩展的版本是一种对协程用户而言易于识别和直观的模式。

更"反应式"的方法是使用而不是通道:

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun produceNumbers() : Flow<Int> = flow {
    for (x in 1..5) {
        println("emit $x")
        emit(x)
    }
    println("Done")
}

fun main() = runBlocking {
    val flow = produceNumbers()
    flow.collect {
        println(it)
    }
    println("Main done")
}

请注意,这种行为会有所不同,除非明确指定(例如使用flowOn(Dispatchers.Default)或将flow {...}替换为channelFlow {...}),否则它将不会在并发协程中启动。

flowOn() 将在哪里使用? - George Udosen
1
在用户端,val flow = produceNumbers().flowOn(Dipsatchers.Default) 将会在默认调度程序(线程池)中运行流的代码,而 collect() 仍将在主线程上运行,因此您可以在这里获得并行性。还有其他方法可以使其并发运行而不是并行运行,但目前没有想到。 - Joffrey
谢谢,你有流程文档的链接吗? - George Udosen
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html - Joffrey
1
我在答案中添加了一些链接。如果您想要通道和流之间的交互,可以查找channelFlowproduceIn - Joffrey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接