学习Flow的时候,看到一个返回Flow的代码.但不明白传入的“块”是如何通过调用
flow.collect { value ->
println(value)
}
字符串
相关代码;
internal inline fun <T> unsafeFlow(crossinline block: suspend FlowCollector<T>.() -> Unit): Flow<T> {
return object : Flow<T> {
override suspend fun collect(collector: FlowCollector<T>) {
collector.block()
}
}
}
suspend fun FlowCollector<Int>.loopFunc() {
for (i in 1..5) {
emit(i)
}
}
val flow: Flow<Int> = unsafeFlow<Int> {
loopFunc()
}
flow.collect { value ->
println(value)
}
型
2条答案
按热度按时间nwnhqdif1#
免责声明:在评论中讨论过这个问题后,很明显混淆主要来自于尾随的lambdas和SAM conversions。作者还问了这个代码实际上是如何工作的。
让我们从基础开始:
FlowCollector
-流中项目的消费者。它是一个被动的一面,项目被发射(推)到它。Flow
-项目来源。可以通过向其提供收集器来使用它们。然后流发出到我们的收集器。loopFunc()
-我们可以称之为生成器函数。它接收一个收集器,并通过将项发射到该收集器中来生成项。它在某种程度上类似于流,因为它接受收集器并向其发出。但它并不是表示项目来源的标准方式-通常,我们使用流。unsafeFlow()
-它将生成器函数转换为流。它创建了一个流,如果我们从它收集(向它提供一个收集器),它所做的唯一事情就是委托给一个存储的生成器函数。现在解释一下这段代码:
字符串
它使用尾随lambda语法和SAM转换。它与以下内容相同:
型
总结一下,代码流程是这样的:
1.我们使用
unsafeFlow()
创建一个流。此流存储loopFunc()
生成器函数,并在收集时简单地委托给它。1.我们创建一个收集器,它只是打印发射到它的项目。
1.我们通过向流提供收集器来从流中收集数据。
1.在
unsafeFlow()
中创建的流只是将收集器传递给loopFunc()
。loopFunc()
运行一个循环,用后续的项调用我们的收集器。1.当循环结束时,我们从
loopFunc()
返回,然后从flow.collect()
函数返回,因此代码可以继续。整个代码可以简化为:
型
但是它在中间使用了一个
Flow
,这增加了复杂性。p8h8hvxi2#
好,你看这个理解对不对。
在kotlinx.coroutines.flow中,它有一个扩展函数,它接受一个函数的参数。
字符串
所以
型
用lambda作为参数调用它。在扩展函数中,它调用Flow示例上的
collect
函数(从unsafeFlow()返回),其中FlowCollector对象具有overrideoverride suspend fun emit(value: T) = action(value)
:型
在unsafeFlow()中:
型
它传入了一个
crossinline block: suspend FlowCollector<T>.() -> Unit
,unsafeFlow
函数签名中的lambda表达式block
可以像FlowCollector的成员函数一样调用。这是通过Kotlin中带有接收器的函数字面量的概念实现的(Kotlin中带有接收器的函数字面量允许您定义被调用的函数,就好像它们是特定接收器类型的成员函数一样)。所以呢
因此,当调用从
unsafeFlow()
返回的Flow的collect(collector: FlowCollector<T>)
时,在其中调用block()
,其调用覆盖emit(value:T),即println(value)
。希望这就是代码片段发生的情况。
更新:@broot是正确的,谢谢!。
fun interface FlowCollector<in T>
是功能(SAM)接口,因此型
它将lambda表达式转换为接口实现,它与:
型