Kotlin可以替代Python的协同产出和发送

什么是一个Kotlin惯用的替代下面的Python协程代码片段:

def generator(): c = 1 while True: op = yield c if op == 'inc': c += 1 elif op == 'mult': c *= 2 # main g = generator() a = g.send(None) # start b = g.send('inc') c = g.send('mult') d = g.send('inc') print([a, b, c, d]) # 1, 2, 4, 5 

所以我需要从协程(通过通道?)获取值,而且还要将值发送回协程。 我需要两个频道吗?

在Python和ES6中存在的那种双向生成器在Kotlin中并不是真正的习惯,因为Kotlin是一种静态类型的语言,因此双向生成器使用起来相当笨拙。 只要看一下上面代码中的g.send(None)就可以理解为什么会这样。 所以,Kotlin标准库和支持库都不提供双向生成器的实现。

但是,Kotlin语言的协程支持是足够通用的,如果需要,可以实现双向生成器,就像在Python和ES6中一样。 相应的实现在这里可用,只需要几十行代码。

通过上面的双向生成器实现,你的Python代码可以直接转换成Kotlin:

 fun generator() = generate<Int, String> { var c = 1 while (true) { val op = yield(c) when (op) { "inc" -> c += 1 "mult" -> c *= 2 } } } fun main(args: Array<String>) { val g = generator() val a = g.next("") // start val b = g.next("inc") val c = g.next("mult") val d = g.next("inc") println("$a $b $c $d") // 1, 2, 4, 5 } 

这个代码的工作方式和Python版本一样好,但是由于多种原因,这种代码并不是惯用的。 首先,Kotlin支持的协程允许定义任意的挂起函数,从而可以以类型安全的方式表达类似的行为,而不需要使用任意的开始标记,也不需要使用字符串来表示操作。 您可以直接定义一个具有incmult的对象作为其第一级挂起操作,或者至少可以更改实现,以便不需要虚拟启动调用。 欢迎大家学习协程设计文档 ,解释Kotlin提供的所有底层原语,并有许多例子帮助您入门。