Posted at

Kotlin coroutineのactorによるFizzBuzz

More than 1 year has passed since last update.

actor楽しい。

class Value(val value: Int, var output: String = "")

fun rule(seed: Int, print: String, next: SendChannel<Value>) = actor<Value> {
for (value in channel) {
next.send(value.apply {
if (value.value % seed == 0) {
this.output += print
}
})
}
}

fun printer() = actor<Value> {
for (value in channel) {
if (value.output.isNotEmpty()) {
println(value.output)
} else {
println(value.value)
}
}
}

fun fizz(next: SendChannel<Value>) = rule(3, "Fizz", next)

fun buzz(next: SendChannel<Value>) = rule(5, "Buzz", next)

使いかたはこう。

fun main(args: Array<String>) = runBlocking<Unit> {

val fizzBuzz = fizz(buzz(printer()))
repeat(100) {
fizzBuzz.send(Value(it + 1))
}
}

出力はこんな感じ。

1

2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
...


どのように動くのか(簡易)


  • 前提


    • Valueクラスは入力値と出力値を表すクラス。

    • rule関数はactorを生成する関数。Valueのoutputにセットするprintという変数と、セットする条件となるseedを持つ


    • fizz(next: SendChannel<Value>)はrule関数のラッパーで、seed=3, print="Fizz"をrule関数に渡す。つまりrule関数はreceiveした値が3で割り切れたらValueのoutputに"Fizz"を追加する


    • buzz(next: SendChannel<Value>)もrule関数のラッパーで、seed=5, print="Buzz"を渡す。


    • printer()は受け取ったValueをprintする



  • 動作


    • repeat関数から0-99までの値が送られてくる

    • 変数fizzBuzz(中身はfizz関数で作ったactor)にValueを作って送る

    • fizzのactorが値をreceiveする(rule関数のfor (value in channel)の所。channelから値を受け取ったら処理が進み、終わったらsuspendして次の値を待つ)

    • 貰った値がルールに沿う場合はValueのoutputを加工する。

    • Valueを次のactorにsendする(buzzのactorに送る)

    • buzzのactorもfizzと同様の処理をして、printerのactorにValueを送る

    • printerのactorが受け取ったValueをprintする




イメージ

こんな感じかな-


まとめ

おもしろい