Scalaにはbreak
もcontinue
もないので、一部のループ動作はもう少し考える必要があります。
ループの終了 早期には、末尾再帰、例外、またはscala.util.control.Breaks
(例外を使用)が必要です。
これの論理的根拠は、goto
と同様に、フローを不明瞭にするフロー構成体であり、より優れた、驚くべき方法で実行できるということです。
しかし、同じ引数をreturn
に使用できるようです。
Scalaがbreak
とcontinue
を意図的に省略したが、return
は省略しなかったのはなぜですか?
Break and Continue:
Scalaについての講演 で、Martin Oderskyはスライド22に中断または続行を含めない3つの理由を示しました。
そして彼は、「私たちはそれらを純粋に図書館でサポートすることができます」と言います。スライド23では、break
を実装するコードを示しています。 Scala十分によくわかりませんが、break
を実装するために必要なのはそのスライドの短いスニペットであり、continue
は同様に短い。
このようなものをライブラリに実装できると、コア言語が簡素化されます。
Martin Odersky、Lex Spoon、Bill Vennersによる「Programming in Scala、Second Edition」では、次の説明が示されています。
break
やcontinue
についての言及がないことにお気づきかもしれません。 Scalaは、関数リテラルとうまくかみ合わないため、これらのコマンドを省略しています...continue
ループ内のwhile
の意味は明らかですが、関数リテラル内では何を意味しますか?...break
とcontinue
を使用せずにプログラミングするには多くの方法があり、関数リテラルを利用する場合、これらの代替案は多くの場合、元のコードよりも短くなる可能性があります。
戻り値:
Returnは動詞、つまり何かを実行するコマンドであるため、スタイルは少し必要不可欠と考えることができます。しかし、それらは純粋に機能的/宣言的な方法で見ることもできます:関数の戻り値が何であるかを定義します(複数の戻り値を持つ関数で、それぞれが部分的な定義しか与えない場合でも)。
同じ本の中で、彼らはreturn
について次のように述べています:
明示的な
return
ステートメントがない場合、Scalaメソッドは、メソッドによって計算された最後の値を返します。メソッドの推奨スタイルは、明示的、特に複数のreturn
ステートメントを避けることです。代わりに、各メソッドを、返される1つの値を生成する式と考えてください。
return
ステートメントが使用されていない場合でも、メソッドは終了して値を返します。そうしないと、クロージャーが機能しないため、クロージャーに関する問題は発生しません。
関数はとにかく値を返さなければならないので、関数リテラルとうまくメッシュすることにも問題はありません。
以前の答えは、比較的制約のないコンテキストで、Scalaの言語全体の方法でbreak
またはcontinue
のセマンティクスを定義する問題を正当化すると思います。
より制約されたコンテキストでbreak
とcontinue
を定義する 小さなライブラリ を書きました:Scala for-comprehensionsによるシーケンスの反復そのコンテキストに焦点を当てることにより、セマンティクスが明確になり、推論しやすくなると私は信じています。
ライブラリはここから入手できます: https://github.com/erikerlandson/breakable
以下は、コードでの表示の簡単な例です。
scala> import com.manyangled.breakable._
import com.manyangled.breakable._
scala> val bkb2 = for {
| (x, xLab) <- Stream.from(0).breakable // create breakable sequence with a method
| (y, yLab) <- breakable(Stream.from(0)) // create with a function
| if (x % 2 == 1) continue(xLab) // continue to next in outer "x" loop
| if (y % 2 == 0) continue(yLab) // continue to next in inner "y" loop
| if (x > 10) break(xLab) // break the outer "x" loop
| if (y > x) break(yLab) // break the inner "y" loop
| } yield (x, y)
bkb2: com.manyangled.breakable.Breakable[(Int, Int)] = com.manyangled.breakable.Breakable@34dc53d2
scala> bkb2.toVector
res0: Vector[(Int, Int)] = Vector((2,1), (4,1), (4,3), (6,1), (6,3), (6,5), (8,1), (8,3), (8,5), (8,7), (10,1), (10,3), (10,5), (10,7), (10,9))