What would be a Kotlin idiomatic alternative to the following python coroutine snippet:
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
So I need get values from the coroutine (via a channel?), but also send the values back into the coroutine. Do I need two channels for that?
Two-way generators of the kind that are present in Python and in ES6 are not really idiomatic in Kotlin, because Kotlin is a statically typed language and therefore two-way generators are quite clumsy to use. Just take a look at the g.send(None)
in the above code to understand why it is so. So, implementation of two-way generators is not provided in Kotlin standard library nor in supporting libraries.
However, coroutines support in Kotlin language is generic enough and two-way generators can be implemented, if needed, to behave just like in Python and ES6. The corresponding implementation is available here and takes just a few dozen lines of code.
With the above implementation of two-way generator, your Python code can be directly translated into Kotlin line-by-line:
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
}
This code works just as well as its Python version, however it is not idiomatic for multitude of reasons. For one, is that coroutines support in Kotlin allows for definition of arbitrary suspending functions and thus makes it possible to express similar behaviour in a type-safe way without resorting to an arbitrary start marker nor using strings to denote operations. You can straightforwardly define an object that has inc
and mult
as its first-class suspending operations, or, at least, change implementation so that a dummy start invocation is not needed. You are welcome to study coroutines design document that explains all the low-level primitives that Kotlin provides and has a number of examples to get you started.
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加