我没有在Kotlin中看到关键字Yield的非常明确的定义。
上面的链接中的示例并没有提及太多,但以下情况,
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]
但上面的例子并没有指出收益率的重要性。教程使用类似的例子来解释什么是收益率,所以它变得有点难以理解以下,
我来自Java世界,因此有点难以理解这个概念。
提前致谢。
您可以将yield()
视为“返回,下次从您停止的位置开始”:
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的东西:
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类中,我们通过使用两个变量来维护显式状态:count
和state
。 sequence
和yield
的组合允许隐含地维持这种状态。
让我们考虑一个示例,您可以在其中生成序列的下一个元素,但是您没有看到实现Java迭代器的简单方法。
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{..}
块,因此调用堆栈是空闲的。
假设我们执行以下操作
fibonacci().take(10).forEach{
println(it)
}
forEach
循环的每次迭代都将从之前的sequence{..}
函数调用中恢复yield
块,并让它运行到下一个yield
函数调用。执行流程将forEach
循环迭代与sequence{..}
块评估混合。您可以尝试编写与Java Iterator
相同的内容来感受Kotlin编译器在幕后所做的事情。
Kotlin中的suspend
函数在语言和标准库方面都是简约的,其余的可以在库中实现。我建议查看kotlinx.coroutines
库以获取更多内部,示例和文档https://github.com/Kotlin/kotlinx.coroutines