なぜScalaには戻りがあるが、壊れて継続しないのか


22

Scalaにはbreakor はありませんcontinue。そのため、ループの動作にはもう少し考えが必要です。

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

この理由は、のようにgoto、それらが流れを不明瞭にする流れの構造であり、より良く、驚くほどではない方法で達成できるということです。

しかし、それらと同じ引数を使用できるようですreturn

なぜScalaはを意図的に省略breakしましたcontinueが、そうではなかったのreturnですか?


1
言語の作者は、反復を構築する方法として末尾再帰を考慮すると想像できます。私はそれを想像することができbreakcontinueいくつかの追加のクリーンアップ機械が必要です。OTOH returnは機能を正常に終了する方法であり、いずれにせよクリーンアップ機構はすでに存在しています。
9000

1
後付けがありますbreakable { for { break; } }が、効率的ではありません。
ジョープエッゲン

関数には実際には理由がないためです。Pythonでも同じです。ブレーク付きforループを使用するたびに、代わりに関数を記述し、ループを関数に入れてreturnを使用できます。これがクリーンコードに関して良い考えではない状況を考えることはできません。パフォーマンスについては、クリーンな方が良いかもしれませんが、パフォーマンスはscalaでは最優先事項ではありません。
ヴァレンテリー14年

2
それがここで答えを持っているようなこの質問のルックス:stackoverflow.com/questions/3770989/...
マイケル・ショー

3
@PaulDraper:のための答えbreakcontinueあなたの質問にし、あなたの質問内のリンクに含まれています。の質問returnは、私がリンクした質問の内容そのものであり、少なくともトップ投票で受け入れられた回答で回答されました。2つの回答をまとめて質問に答えない場合は、質問を編集して明確にすることができます。
マイケルショー

回答:


16

中断して続行:

ではScalaの話、マーティン・オーダーズキーは休憩を含めたり、スライド22に継続しない3つの理由を与えました:

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

そして彼は、「ライブラリで純粋にサポートできる」と言います。スライド23で、彼はを実装するコードを提供しますbreak。私はScalaを確実に十分に理解していませんが、そのスライドの短いスニペットが実装breakに必要なすべてであり、continue同様に短いコードで実装できるようです。

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

Martin Odersky、Lex Spoon、Bill Vennersによる「Scalaのプログラミング、第2版」では、以下の説明が与えられています。

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

戻り値:

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

同じ本で、彼らは次のことを言っていますreturn

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

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

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


2
帰還に関しては、いくつかの軽度の危険があるようです:tpolecat.github.io/2014/05/09/return.html
bbarker

0

以前の答えは、セマンティクスを定義する問題に正義があると思います breakcontinue、比較的制約のないコンテキストを使用して、Scalaのまたは言語全体。

私は定義する小さなライブラリを書きましたbreakし、continueより多くの制約のコンテキストで:反復シーケンスを超えるScalaの経由のため、内包。そのコンテキストに注目することで、セマンティクスが明確になり、推論しやすくなると思います。

ライブラリはこちらから入手できます: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))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.