web-dev-qa-db-ja.com

なぜScalaリターンがあるが、ブレークして続行しないのか

Scalaにはbreakcontinueもないので、一部のループ動作はもう少し考える必要があります。

ループの終了 早期には、末尾再帰、例外、またはscala.util.control.Breaks(例外を使用)が必要です。

これの論理的根拠は、gotoと同様に、フローを不明瞭にするフロー構成体であり、より優れた、驚くべき方法で実行できるということです。

しかし、同じ引数をreturnに使用できるようです。

Scalaがbreakcontinueを意図的に省略したが、returnは省略しなかったのはなぜですか?

22
Paul Draper

Break and Continue:

Scalaについての講演 で、Martin Oderskyはスライド22に中断または続行を含めない3つの理由を示しました。

  • それらは少し必須です。多くの小さな関数をよりよく使用します。
  • クロージャーとの相互作用方法を発行します。
  • それらは必要ありません!

そして彼は、「私たちはそれらを純粋に図書館でサポートすることができます」と言います。スライド23では、breakを実装するコードを示しています。 Scala十分によくわかりませんが、breakを実装するために必要なのはそのスライドの短いスニペットであり、continueは同様に短い。

このようなものをライブラリに実装できると、コア言語が簡素化されます。

Martin Odersky、Lex Spoon、Bill Vennersによる「Programming in Scala、Second Edition」では、次の説明が示されています。

breakcontinueについての言及がないことにお気づきかもしれません。 Scalaは、関数リテラルとうまくかみ合わないため、これらのコマンドを省略しています... continueループ内のwhileの意味は明らかですが、関数リテラル内では何を意味しますか?... breakcontinueを使用せずにプログラミングするには多くの方法があり、関数リテラルを利用する場合、これらの代替案は多くの場合、元のコードよりも短くなる可能性があります。

戻り値:

Returnは動詞、つまり何かを実行するコマンドであるため、スタイルは少し必要不可欠と考えることができます。しかし、それらは純粋に機能的/宣言的な方法で見ることもできます:関数の戻り値が何であるかを定義します(複数の戻り値を持つ関数で、それぞれが部分的な定義しか与えない場合でも)。

同じ本の中で、彼らはreturnについて次のように述べています:

明示的なreturnステートメントがない場合、Scalaメソッドは、メソッドによって計算された最後の値を返します。メソッドの推奨スタイルは、明示的、特に複数のreturnステートメントを避けることです。代わりに、各メソッドを、返される1つの値を生成する式と考えてください。

returnステートメントが使用されていない場合でも、メソッドは終了して値を返します。そうしないと、クロージャーが機能しないため、クロージャーに関する問題は発生しません。

関数はとにかく値を返さなければならないので、関数リテラルとうまくメッシュすることにも問題はありません。

16
Michael Shaw

以前の答えは、比較的制約のないコンテキストで、Scalaの言語全体の方法でbreakまたはcontinueのセマンティクスを定義する問題を正当化すると思います。

より制約されたコンテキストでbreakcontinueを定義する 小さなライブラリ を書きました: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))
0
eje