我有一些格式的代码:
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不允许使用这种模式,我有一些直觉,这将非常有用。
将所有与协同线相关的函数移到一个类中,它就可以工作了。仍然不清楚为什么跨类协同函数调用不起作用
发布于 2022-11-04 00:28:32
myProducerFunction()是CoroutineScope的扩展函数,所以您只能在CoroutineScope上调用它。
这导致了一种尴尬的情况:当您在一个类中定义扩展函数时,很难从该类外部调用。为了能够调用另一个函数,您必须将其拥有的类作为接收者引入作用域,这可以使用run { }作用域函数来完成,如下所示:
fun functionToBeCalledByApplication(scope: CoroutineScope) = runBlocking {
MyProducerClass().run { scope.myConsumerFunction(myProducerFunction()) }
}上面,我把一个CoroutineScope变成一个函数参数。您也可以将其改为扩展函数,但随后将问题传递给希望调用此函数的应用程序类:
fun CoroutineScope.functionToBeCalledByApplication() = runBlocking {
MyProducerClass().run { myConsumerFunction(myProducerFunction()) }
}出于这些原因,您通常希望避免在类中定义公共扩展函数。在这种情况下,根据这些类的使用方式,我要么将CoroutineScope作为关联类的成员属性提供,要么将其作为这些函数中的常规函数参数。
很快,这个问题就会解决。在Kotlin中有一个叫做“上下文接收器”的实验特性,我认为它计划在Kotlin 1.8或1.9中稳定下来。您将能够为函数定义上下文接收器,因此接收方需要在作用域内调用函数,但不必调用该对象上的函数。在即将发布的功能中,您可以像这样定义函数:
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,它也可以在它自己的协同机制中这样做。
https://stackoverflow.com/questions/74310493
复制相似问题