定义一个最简单的 Lambda 表达式,并可以多次调用它:
val f: () -> Unit = {
println("foo")
}
fun main() {
f() // foo
f() // foo
}
很容易可以让这个 Lambda 表达式支持挂起,添加 suspend 修饰符:
val f: suspend () -> Unit = {
delay(1_000)
println("foo")
}
suspend fun main() {
f() // foo
f() // foo
}
通过 Kotlin 高阶函数的定义,函数可以作为参数传递给其它函数。 这里,我们让 Lambda 表达式接收一个挂起函数,并将参数称为 emit :
val f: suspend (suspend (String) -> Unit) -> Unit = { emit ->
delay(1_000)
emit("foo")
}
suspend fun main() {
f {
println(it) // foo
}
}
通常我们更习惯于通过接口来定义某种“模式”,而不是函数类型。 这里,可以定义一个函数式接口:
fun interface XFlowCollector {
suspend fun emit(value: String)
}
// 更改后:
val f: suspend (XFlowCollector) -> Unit = {
delay(1_000)
it.emit("foo")
}
suspend fun main() {
f {
println(it) // foo
}
}
在 it 上调用 emit 并不方便,此时可以将 XFlowCollector 作为 Receiver, 那么在函数体内,可以不再使用 “it”:
// 更改后:
val f: suspend XFlowCollector.() -> Unit = {
delay(1_000)
emit("foo")
}
suspend fun main() {
f {
println(it) // foo
}
}
同样的,更改后的 Lambda 表达式 f,是否可以改写成接口的形式呢? 我们将接口称为 XFlow :
interface XFlow {
suspend fun collect(collector: XFlowCollector)
}
suspend fun main() {
val xFlow = object : XFlow {
override suspend fun collect(collector: XFlowCollector) {
// TODO:
}
}
xFlow.collect {
println(it)
}
}
此时,匿名对象 xFlow 调用 collect 之后,要执行的就是 "TODO",而这个 "TODO",就是上面的 f,即:
suspend fun main() {
val xFlow = object : XFlow {
override suspend fun collect(collector: XFlowCollector) {
collector.f()
}
}
xFlow.collect {
println(it) // foo
}
}
最后,我们定义一个顶级函数,来简化这个流程:
fun xFlow(f: suspend XFlowCollector.() -> Unit) = object : XFlow {
override suspend fun collect(collector: XFlowCollector) {
collector.f() // 调用传入的 f
}
}
suspend fun main() {
val xFlow = xFlow {
emit("bar")
}
xFlow.collect {
println(it) // bar
}
}
最后的最后,使用泛型参数来替换String,让 xFlow 可以支持任意类型:
fun interface XFlowCollector<X> {
suspend fun emit(value: X)
}
interface XFlow<X> {
suspend fun collect(collector: XFlowCollector<X>)
}
fun <X> xFlow(f: suspend XFlowCollector<X>.() -> Unit) = object : XFlow<X> {
override suspend fun collect(collector: XFlowCollector<X>) {
collector.f()
}
}
到此为止,以上几乎是 Flow 的实现方式!简单地说,以下为例:
suspend fun main() {
val xFlow = xFlow {
delay(1_000)
emit("bar")
}
xFlow.collect {
println(it)
}
}
每当调用 collect 时,函数会执行:
{
delay(1_000)
emit("bar")
}
每当调用到 emit 时,函数会执行:
{
println(it)
}
这就是 Flow 的工作原理!
特别的,如果一开始,我们不是定义函数式接口,仅定义最普通的接口,这里更能直接看出端倪:
interface XFlowCollector {
suspend fun emit(value: String)
}
suspend fun main() {
val xFlow = xFlow {
delay(1_000)
emit("bar") // 调用 emit,即是调用 “ println(it) ”
}
xFlow.collect(object : XFlowCollector {
override suspend fun emit(value: String) {
println(value)
}
})
}