kotlin.coroutines包下的API

kotlin.coroutines.experimental包下的应用级别的函数仅包括:

  • buildSequence()
  • buildIterator()

这些内容都被一起装进了kotlin-stdlib,因为它们和序列相关。实际上,这些函数(这里可以限制在上述的buildSequence()中)实现了生成器,比如,提供一种代价较小的生成懒加载序列的方式:

val fibonacciSeq = buildSequence {
    var a = 0
    var b = 1
    yield(1)
    while (true) {
        yield(a + b)
        val tmp = a + b
        a = b
        b = tmp
    }
}

这样通过创建一个协同程序的i调用yield()函数生成了一个懒加载、潜在的无限的连续斐波那契序列。当遍历这样的一个序列时,每遍历一次就会执行协同程序的另一部分来生成下一个数字。因此,我们可以传入任何有限大小的数字列表,比如

fibonacciSeq.take(8).toList()

输出结果:

[1, 1, 2, 3, 5, 8, 13, 21]

协同程序在实现这样的功能时代价较小一些。

为了演示这种序列的真实的懒加载特性,我们在buildSequence()方法中打印一些调试输出信息:

val lazySeq = buildSequence {
    print("START ")
    for (i in 1..5) {
        yield(i)
        print("STEP ")
    }
    print("END")
}
// Print the first three elements of the sequence
lazySeq.take(3).forEach { print("$it ") }

执行上面的代码查看一下是否我们打印出了前三个元素,并且这三个元素e被STEP交替连接。这意味着计算确实是在需要的时候才会计算。打印1时我们仅仅是执行到第一个yield(i)的位置,并且沿着代码执行顺序打印了START,然后打印2我们需要处理下一个yield(i),并且打印出STEP。对于打印3来说,道理类似。下一个STEP将不会打印出(END同样不会被打印出),因为我们没有在请求后面的序列元素。

为了可以立刻生产一个集合或序列值,可以使用yieldAll()函数:

val lazySeq = buildSequence {
    yield(0)
    yieldAll(1..10)
}
lazySeq.forEach { print("$it ") }

buildIterator()使用起来和buildSequence()类似,但是其返回懒加载迭代器。

可以添加自定义的生成逻辑到buildSequence(),这需要实现一个SequenceBuilder类的挂起扩展函数(请查看上述的@RestrictsSuspension注解)。

suspend fun SequenceBuilder<Int>.yieldIfOdd(x: Int) {
    if (x % 2 != 0) yield(x)
}
val lazySeq = buildSequence {
    for (i in 1..10) yieldIfOdd(i)
}

results matching ""

    No results matching ""