for 式内での変数束縛の罠
今日のScalaハマりポイント: for 式内の変数束縛のタイミングが直観に合わない。 挙動をちゃんと知っていれば理解は出来るけれど、気を使って書かなければいけないのはデメリット。
普通に読むと、i
を束縛した後、best
を束縛して、j
を回す、それが終わったらまたi
を束縛してbest
を束縛して…と読めて、結果としてWrappedArray(21, 22, 23, 24, 25)
が出力されるはずだと思うわけだけど、実際にはそうはならず、WrappedArray(1, 2, 3, 4, 5)
が出力される。
scala -Xprint:parser
で for式の部分を見てみると、
となっていて、最初のループは foreach ではなくて、 map に変換されているのが分かる。
つまり、j
のループが回る前に best
がi
のmapとして固定されてしまうわけだ。
for内の要素が不変である事が前提ならば特に問題ないのだけど、
上記のようにループ中に要素が変更される場合には、一般的な二重ループの直観とずれが生じてしまう。
期待する結果を得るには、
のように書かなければならない。これは期待通り foreach に変換される。
あるいは、すこしオーバーヘッドが出そうだが
のような書き方をしても
と、期待通りの動作となる。