web-dev-qa-db-ja.com

コトリンの利回り関数を理解する

Kotlinの yield 関数の明確な定義がわかりません。

上記のリンクの例では、以下についてはあまり言及されていませんが、

val sequence = sequence {
    val start = 0
    // yielding a single value
    yield(start)
    // yielding an iterable
    yieldAll(1..5 step 2)
    // yielding an infinite sequence
    yieldAll(generateSequence(8) { it * 3 })
}

println(sequence.take(7).toList()) // [0, 1, 3, 5, 8, 24, 72]

しかし、上記の例は歩留まりの重要性を指摘していません。

  • 一時停止機能とはどういう意味ですか?
  • どのシナリオでそれは有利になりますか?
15
Ahmed

yield()は「戻り、次に停止したところから開始する」と考えることができます。

val sequence = sequence {
    val start = 0
    yield(start) // first return
    yieldAll(1..5 step 2) // if called again, will start from here
    yieldAll(generateSequence(8) { it * 3 }) // if called more that six times, start from here
}

ステートマシンなどを作成しますが、Javaのようなものに変換できます。

class Seq {
    private AtomicInteger count = new AtomicInteger(0);
    private int state = 0;

    public int nextValue() {
        if (count.get() == 0) {
           return state;
        }
        else if (count.get() >= 1 && count.get() <= 5) {
           state += 2;
           return state;
        }
        else {
           state *= 3;
           return state;
        }
    }
}

Javaクラスでは、countstateの2つの変数を使用して明示的な状態を維持しています。sequenceyieldの組み合わせこの状態を暗黙的に維持できるようにします。

15
Alexey Soshin

シーケンスの次の要素を生成できるが、Javaイテレータを実装する簡単な方法がわからない場合の例を考えてみましょう。


fun fibonacci() = sequence {
  var a_0 = 1
  var a_1 = 1

  // this sequence is infinite
  while(true) {
    val a_n = a_0 + a_1
    a_0 = a_1
    a_1 = a_n

    //this is a suspend function call
    yield(a_0)
  }
}

この例では、yield関数を使用して、シーケンスの次の要素を返します。この関数は、Kotlinのsuspend関数の例です。関数の呼び出しはsequence{..}ブロックの実行を一時停止するため、呼び出しスタックは解放されます。

次のようにするとします

fibonacci().take(10).forEach{ 
   println(it) 
}

forEachループを繰り返すたびに、以前のyield関数呼び出しからsequence{..}ブロックが再開され、次のyield関数呼び出しまで実行されます。実行フローは、forEachループの反復とsequence{..}ブロックの評価を組み合わせます。 Java Iteratorと同じように書いてみて、Kotlinコンパイラが舞台裏で行っていることを感じてみてください。

Kotlinのsuspend関数は、言語と標準ライブラリ側で最小限に抑えられ、残りはライブラリに実装できます。 kotlinx.coroutinesライブラリで詳細、例、ドキュメントを確認することをお勧めします https://github.com/Kotlin/kotlinx.coroutines

4
Eugene Petrenko