読者です 読者をやめる 読者になる 読者になる

【Scala】for式のyieldがよくわかんなかった

Scala

scalaってなんか難しいんですよね。

最近いまいち理解してなかったのがfor式のyield。
色々自分で書いてみてなんとなくこれかなって結論に達した。
コップ本で学習してんのになんで理解できないのよって、自分で思う。悲しい。

よくわからなかった点

yieldをつかわない時

val ary = Array(1, 2, 3)
for (num <- ary) {
  println(num)
}
1
2
3

yieldを使った時

val ary = Array(1, 2, 3)
for (num <- ary) yield {
  println(num)
} 
1
2
3

これ両方共numの値を出力しているので結果は一緒


yield使っても使わなくてもコレクションの中身に対して何かできるなら
yield使わんでもよくない??って疑問に思った。


もうひとつサンプル。

val ary = Array(1, 2, 3)
for (num <- ary if num % 2 == 0) {
  println(num)
}
2
val ary = Array(1, 2, 3)
for (num <- ary if num % 2 == 0) yield {
  println(num)
}
2

配列の要素を順番にnumに入れつつ、
if文で偶数の場合だけにしている。
その結果をprintlnで表示しているのだが、
こちらもyieldを使っても使わなくても一緒。

???yieldって何者なんだ・・・??

yieldはこう使う

結論として、yieldはfor式で得られた結果に対して新たにコレクションを生成する。
本にしっかりと書いてあるし、yieldで検索すればみんなそう書いてる。
ちゃんと読んではいたんだけど、おつむが弱かった。。

どういうことかというと、

val ary = Array(1, 2, 3)
val evens = for (num <- ary if num % 2 == 0) yield num

for式で配列aryの要素に対してフィルターをかけたとする。
というか上のサンプルでは偶数フィルターをかけている。
結果として、「2」だけがnumに入る。
その「2」というフィルター後の結果で新しくコレクション(配列)を生成して返すのがyield
なのでevensという変数にはArray(2)が入っているということだ。

それでは、yieldをつかわない版ではどうなるか。

val ary = Array(1, 2, 3)
val evens = for (num <- ary if num % 2 == 0) {
    num
  } 

if式の結果によって中括弧の中のnumには2だけが入るが、新しくコレクションを生成しているわけではないので、
結果はUnitが帰りevensに入る。


yieldを使うことによってfor式の結果をコレクションとして返せるっていうことでした。