了解Kotlin的收益函数

Understanding Kotlin's yield function

我在Kotlin中看不到yield函数的非常清晰的定义。

上面链接中的示例未提及太多,但以下内容

1
2
3
4
5
6
7
8
9
10
11
val sequence = sequence {
    val start = 0
    // yielding a single value
    yield(start)
    // yielding an iterable
    yieldAll(1..5 step 2)
    // yielding an infinite sequence
    yieldAll(generateSequence(8) { it * 3 })
}

println(sequence.take(7).toList()) // [0, 1, 3, 5, 8, 24, 72]

但是上面的例子并没有指出产量的重要性。

  • 这是一个暂停功能是什么意思?
  • 在什么情况下会有利?

您可以将yield()视为"返回,下一次从您停止的地方开始":

1
2
3
4
5
6
val sequence = sequence {
    val start = 0
    yield(start) // first return
    yieldAll(1..5 step 2) // if called again, will start from here
    yieldAll(generateSequence(8) { it * 3 }) // if called more that six times, start from here
}

它创建状态机和内容,但是您可以将其转换为Java中的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Seq {
    private AtomicInteger count = new AtomicInteger(0);
    private int state = 0;

    public int nextValue() {
        if (count.get() == 0) {
           return state;
        }
        else if (count.get() >= 1 && count.get() <= 5) {
           state += 2;
           return state;
        }
        else {
           state *= 3;
           return state;
        }
    }
}

在Java类中,我们通过具有两个变量来维护显式状态:countstatesequenceyield的组合允许隐式维护此状态。

请注意,yield()是一个挂起函数,因此只能从另一个suspend函数或协程内部调用。


让我们考虑一个示例,在该示例中您可以生成序列的下一个元素,但是看不到实现Java迭代器的简便方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fun fibonacci() = sequence {
  var a_0 = 1
  var a_1 = 1

  // this sequence is infinite
  while(true) {
    val a_n = a_0 + a_1
    a_0 = a_1
    a_1 = a_n

    //this is a suspend function call
    yield(a_0)
  }
}

该示例使用yield函数返回序列的下一个元素。该函数是Kotlin中suspend函数的示例。对该函数的调用将暂停sequence{..}块的执行,因此调用堆栈是空闲的。

假设我们执行以下操作

1
2
3
fibonacci().take(10).forEach{
   println(it)
}

forEach循环的每次迭代都会从上一个yield函数调用中恢复sequence{..}块,并使其运行到下一个yield函数调用。执行流程将forEach循环迭代与sequence{..}块评估混合在一起。您可以尝试编写与Java Iterator相同的代码,以了解Kotlin编译器在后台执行的操作。

Kotlin中的

suspend函数在语言和标准库方面都做到了极简,其余的都可以在库中实现。我建议检查kotlinx.coroutines库以获取更多内幕,示例和文档
https://github.com/Kotlin/kotlinx.coroutines