Kotlin 替代 Python 协程的 yield 和 send
Kotlin alternative to Python's coroutine yield and send
以下 python 协程片段的 Kotlin 惯用替代方法是什么:
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 中一样。相应的实现可用 here 并且只需几十行代码。
通过以上双向生成器的实现,你的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 中的协程支持允许定义任意暂停函数,因此可以以类型安全的方式表达类似的行为,而无需求助于任意开始标记或使用字符串来表示操作。您可以直接定义一个具有 inc
和 mult
作为其第一个 class 暂停操作的对象,或者至少更改实现以便不需要虚拟启动调用。欢迎您学习 coroutines design document,它解释了 Kotlin 提供的所有低级原语,并有许多示例可以帮助您入门。
以下 python 协程片段的 Kotlin 惯用替代方法是什么:
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 中一样。相应的实现可用 here 并且只需几十行代码。
通过以上双向生成器的实现,你的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 中的协程支持允许定义任意暂停函数,因此可以以类型安全的方式表达类似的行为,而无需求助于任意开始标记或使用字符串来表示操作。您可以直接定义一个具有 inc
和 mult
作为其第一个 class 暂停操作的对象,或者至少更改实现以便不需要虚拟启动调用。欢迎您学习 coroutines design document,它解释了 Kotlin 提供的所有低级原语,并有许多示例可以帮助您入门。