首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >kotlin consumeEach() vs receive()

kotlin consumeEach() vs receive()
EN

Stack Overflow用户
提问于 2022-11-03 23:08:08
回答 1查看 35关注 0票数 0

我有一些格式的代码:

代码语言:javascript
复制
 class MyProducerClass {
        fun CoroutineScope.myProducerFunction(): ReceiveChannel<someClass> = produce {
            // send some stuff to a channel
        }
    }

    class MyConsumerClass {
        val producerObject = MyProducerClass()

        fun CoroutineScope.myConsumerFunction(channel: ReceiveChannel<someClass>) = launch {
            // Consume stuff from the channel
        }
        
        fun functionToBeCalledByApplication() = runBlocking {
            MyProducerClass().myConsumerFunction(myProducerFunction())
        }
    }

但是,myProducerFunction似乎不能从MyConsumerClass内部访问。有人能解释一下为什么吗?我对kotlin非常陌生,对于为什么coroutines不允许使用这种模式,我有一些直觉,这将非常有用。

将所有与协同线相关的函数移到一个类中,它就可以工作了。仍然不清楚为什么跨类协同函数调用不起作用

EN

回答 1

Stack Overflow用户

发布于 2022-11-04 00:28:32

myProducerFunction()是CoroutineScope的扩展函数,所以您只能在CoroutineScope上调用它。

这导致了一种尴尬的情况:当您在一个类中定义扩展函数时,很难从该类外部调用。为了能够调用另一个函数,您必须将其拥有的类作为接收者引入作用域,这可以使用run { }作用域函数来完成,如下所示:

代码语言:javascript
复制
fun functionToBeCalledByApplication(scope: CoroutineScope) = runBlocking {
    MyProducerClass().run { scope.myConsumerFunction(myProducerFunction()) }
}

上面,我把一个CoroutineScope变成一个函数参数。您也可以将其改为扩展函数,但随后将问题传递给希望调用此函数的应用程序类:

代码语言:javascript
复制
fun CoroutineScope.functionToBeCalledByApplication() = runBlocking {
    MyProducerClass().run { myConsumerFunction(myProducerFunction()) }
}

出于这些原因,您通常希望避免在类中定义公共扩展函数。在这种情况下,根据这些类的使用方式,我要么将CoroutineScope作为关联类的成员属性提供,要么将其作为这些函数中的常规函数参数。

很快,这个问题就会解决。在Kotlin中有一个叫做“上下文接收器”的实验特性,我认为它计划在Kotlin 1.8或1.9中稳定下来。您将能够为函数定义上下文接收器,因此接收方需要在作用域内调用函数,但不必调用该对象上的函数。在即将发布的功能中,您可以像这样定义函数:

代码语言:javascript
复制
class MyProducerClass {
    context(CoroutineScope)
    fun myProducerFunction(): ReceiveChannel<someClass> = produce {
            // send some stuff to a channel
    }
}

class MyConsumerClass {
    val producerObject = MyProducerClass()

    context(CoroutineScope)
    fun myConsumerFunction(channel: ReceiveChannel<someClass>) = launch {
        // Consume stuff from the channel
    }

    context(CoroutineScope)
    fun functionToBeCalledByApplication() = runBlocking {
        MyProducerClass().myConsumerFunction(myProducerFunction())
    }
}

现在,CorouineScope只需要作为接收方在作用域内才能调用这些函数,而不必成为调用函数的对象。因此,在应用程序类中,如果您在类似于launch的协同线函数中调用该函数,它将工作得很好,因为CoroutineScope是一个接收器。

附带注意,您几乎不会在生产代码中看到runBlocking,因为它违背了使用协同服务的目的。它只用于连接非协同代码和协同,比如当您使用一个库,它处理自己的多线程,但需要能够从该库的后台线程调用挂起函数。将最后一个函数改为suspend函数会更合适。调用它的应用程序代码无论如何都需要提供一个CoroutineScope,它也可以在它自己的协同机制中这样做。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74310493

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档