自分用　Flowについて簡単にまとめてみた

Kotlin独自の機能ピックアップ
Flowについて簡単にまとめてみました。

Flowとは？
---
コルーチンをベースにした非同期プログラミングのうち、
Flowは<font color="red">「連続的な非同期なデータ」</font>を表現し、処理するための機能です。
そのため、Flowを非同期に処理を行える「データ ストリーム」と考えることもできます。

データ ストリームには、以下の 3 つのエンティティがあります。
***プロデューサ***
ストリームに出力するデータを生成します。コルーチンであるため、Flow は非同期にデータを生成できます。
***インターミディアリ***
ストリームに出力された各値またはストリームそのものを変更できます。（必要な場合）
***コンシューマ***
ストリームから得られた値を使用します。
引用（https://developer.android.com/kotlin/flow?hl=ja）



Flowの使い方
---
Flowを使うには、<font color="red">FlowビルダーAPI</font>を使用します。
まずは以下のコードを見てみてください。
```
import kotlinx.coroutines
import kotlinx.coroutines.flow

fun sampleFlow() = flow {
    for (i in 1..3) {
        delay(1000) // 非同期処理の模擬
        emit(i)     // 値を生成
    }
}

fun main() {
    CoroutineScope(Dispatchers.IO).launch {
            sampleFlow()
                .collect { value ->
            println(value)
        }
    }
}
```
```
// main()を呼んだ結果
1,2,3
```
これを細かく解説していきます。

sampleFlow()の処理
---
プロデューサの役割を果たし、ストリームに出力するデータを生成します。
***Flow \<Int>***
Flow\<Int>は、非同期で整数の連続的なストリームを表現するための型です
***flow｛～～～｝***
＝でつながれているflow｛～～～｝は、Flowを生成するための flowビルダー関数です。
flowビルダー関数の中では、連続的な非同期なデータを処理します。
***emit()***
データを処理したあとは、emit()（直訳＝放出）して値を生成します。
```
fun sampleFlow() = flow {
    for (i in 1..3) {
        delay(1000) // 非同期処理の模擬
        emit(i)     // 値を生成
    }
}
```
今回のコードはiが3になるまでの処理を非同期でwhile(true){~}で繰り返しデータを生成し続けることも可能です。
しかし、あくまでもデータを生成しただけでこのままでは使用することができません。

main()の処理
---
***CoroutineScope(Dispatchers.IO).launch{～～～}***
非同期に処理を行うことができます。
***sampleFlow().collect {～}***
この中の処理は順序だてて説明します。
①一番最初にsampleFlow() 関数が呼ばれ、flow { ... } ビルダー内のコードが非同期に実行されます。しかしまだデータは発行されるわけではありません。
②simpleFlow()の戻り値である Flowインスタンスが得られます。
③.collect { println(it) } メソッドが呼ばれると、実際にデータの生成が開始されます。（トリガー）この時、flowビルダー内のコードが実行され、1から3までの整数が順次発行されます。
④各データ（Value）が発行されるたびに、collectメソッドのラムダ式が実行され、println(it)が呼ばれます
```
fun main() {
    CoroutineScope(Dispatchers.IO).launch {
            sampleFlow()
                .collect { value ->
            println(value)
        }
    }
}

```

その他のメソッド
---
Flow クラスには、さまざまなメソッドが提供されており、これらを組み合わせて
データを操作できます。

***.map***
.map メソッドは、各要素に対して変換関数を適用し、新しい要素のFlowを生成します。
しかし、実際に新しい要素を発行するのではなく、変換された要素が元の Flow の要素として発行されます。
```
// map 各要素を2倍に変換
sampleFlow()
    .map { it * 2 }
    .collect { println(it) }
// 出力:2,4,6
```  

***.filter:***
.filter メソッドは、条件に合致する要素だけを含む新しい Flow を生成します。
```
// 2. filter: 条件を満たす要素だけを含む
simpleFlow()
    .filter { it > 1 }
    .collect { println(it) }
// 出力:2,3
```
***.transform***
.transform メソッドは、各要素に対して変換関数を適用し、新しい要素を発行するための柔軟なメソッドです。
```
// 3. transform: 各要素を2倍に変換
simpleFlow()
    .transform { emit(it * 2) }
    .collect { println(it) }
// 出力:2,4,6
```
***.onEach***
.onEach メソッドは、各要素に対して副作用を実行し、元の Flow をそのまま返します。
```
// 4. onEach: 各要素を処理しても元のFlowは変わらない
simpleFlow()
    .onEach { println("Processing: $it") }
    .collect { println(it) }
// 出力: Processing: 1,1, Processing: 2,2, Processing: 3,3
```
***.zip***
.zip メソッドは、複数の Flow を結合し、対応する位置の要素をペアとして新しい Flow を生成します。
```
// 5. zip: 2つのFlowを組み合わせて新しいFlowを生成
val flow1 = flowOf(1, 2, 3)
val flow2 = flowOf("A", "B", "C")
flow1.zip(flow2) { a, b -> "$a - $b" }
        .collect { println("zip: $it") }
// 出力: zip: 1 - A, zip: 2 - B, zip: 3 - C
```
***.flatMapConcat***　
.flatMapConcat メソッドは、各要素に対して非同期に別の Flow を生成し、それらの Flow を直列に結合します。
```
// 6. flatMapConcat: 各要素に対して別のFlowを生成し、直列に結合
simpleFlow()
    .flatMapConcat { flowOf(it, it * 2, it * 3) }
    .collect { println(it) }
    // 出力: 1,2,3,2,4,6,3,6,9
```

最後に
---
flow難しい！