Kotlin 1.4からFlowのcombine()がより綺麗に書けるようになった(suspend conversion on callable references)
今回は小ネタ。Kotlinがますます可愛いという話をします。
Kotlin 1.4からsuspend conversion on callable referencesがsupportされました。
これ、Kotlin 1.4.0 にあげたらcompile通るようになった。リリース見てみたらSuspend conversion on callable referencesが1.4.0からsupportされるようになってる! 🎉🎉🎉🎉https://t.co/AKPymXsjms
— Atsuko Fukui (@muumuumuumuu) 2020年9月25日
(^ もう数ヶ月も前のtweet...)
リリースノートではさらっと
In addition to suspend conversion on lambdas, Kotlin now supports suspend conversion on callable references starting from version 1.4.0.
としか書かれていないのであまり気に留めた人もいないんじゃないかなと思いますが、これによってKotlin coroutineの Flow#combine()
がより綺麗に書けるケースがあります。
例えば、二つのflowをcombineして、それをそのまま collect に渡したい場合、1.4より前ではこのような書き方ができませんでした。
suspend fun foo() { combine( flowA, flowB, ::Pair ).collect { (a: Int, b: Int) -> println("$a and $b") } } val flowA = flowOf(1, 2) val flowB = flowOf(3, 4)
1.4より前だと上記のコードはコンパイルエラーになります。combine()の第3引数はsuspend function lamdbaなので、suspendじゃないPiar
クラスのコンストラクタは受け付けてもらえません。1.4からはsuspendに自動で変換してくれるようになったので、上記のコードは問題なく動きます。
ちなみに、collect()
の引数のlambdaの引数(a: Int, b: Int)
はdestructuring declarationsを使っていて、いちいちPairのfirst/secondに名前を付け直したりしなくてもここでa
やb
といった名前をつけられます。可愛い。
a, bの後ろの型の明示は省略可能ですが、destructuring declarationsを使っているので()
はないと動きません。
combine( flowA, flowB, ::Pair ).collect { (a, b) -> // OK println("$a and $b") }
combine( flowA, flowB, ::Pair ).collect { a: Int, b: Int -> // NG (コンパイルエラー) println("$a and $b") }
1.4より前はどういうコードを書いていたか参考までに残しておきます。やはり少し冗長に見えます。
suspend fun fooBefore4_1() { combine( flowA, flowB ) { a, b -> a to b }.collect { val a = it.first val b = it.second println("$a and $b") } } val flowA = flowOf(1, 2) val flowB = flowOf(3, 4)
言いたいことは以上です。