52

私はCourseraのScalaコースをフォローしています。OderskyのScalaの本も読み始めました。

私がよく耳にするのは、関数型言語で例外をスローするのは良い考えではないということです。なぜなら、それは制御フローを壊し、通常は失敗または成功のいずれかを返すからです。また、Scala2.10はその方向に進むTryを提供するようです。

しかし、本とコースでは、マーティン・オーダスキーは(少なくとも今のところ)例外が悪いとは言っていないようで、彼はそれらを頻繁に使用しています。また、メソッドがassert/requireになっていることに気づきました...

最後に、ベストプラクティスに従いたいので少し混乱していますが、それらは明確ではなく、言語は双方向に進んでいるようです...

その場合、誰かが私に何を使うべきか説明してもらえますか?

4

2 に答える 2

50

基本的なガイドラインは、本当に例外的なものに例外を使用することです**。「普通な障がい」の場合は、Optionまたはを使用することをお勧めしますEither。誰かが間違った方法でくしゃみをしたときに例外がスローされるJavaとインターフェイスしている場合は、Try安全を確保するために使用できます。

いくつか例を見てみましょう。

マップから何かをフェッチするメソッドがあるとします。何がうまくいかない可能性がありますか?さて、 segfault *スタックオーバーフローのような劇的で危険なもの、または要素のような期待されるものが見つかりません。segfaultスタックオーバーフローで例外をスローさせますが、単に要素が見つからない場合Option[V]は、値または例外(またはnull)の代わりにを返さないのはなぜですか?

ここで、ユーザーがファイル名を入力することになっているプログラムを作成しているとします。さて、何かがうまくいかなかったときにすぐにプログラムを救済するつもりがないのなら、それが進むべきEither道です:

def main(args: Array[String]) {
  val f = {
    if (args.length < 1) Left("No filename given")
    else {
      val file = new File(args(0))
      if (!file.exists) Left("File does not exist: "+args(0))
      else Right(file)
    }
  }
  // ...
}

ここで、スペースで区切られた数値を含む文字列を解析するとします。

val numbers = "1 2 3 fish 5 6"      // Uh-oh
// numbers.split(" ").map(_.toInt)  <- will throw exception!
val tried = numbers.split(" ").map(s => Try(s.toInt))  // Caught it!
val good = tried.collect{ case Success(n) => n }

したがって、(少なくとも)さまざまなタイプの障害に対処するための3つの方法がありOptionます。Either物事がうまくいくかどうか(または、実際には、相互に排他的な2つのオプションがある場合)、何がうまくいかなかったかについての情報を保存したい場合。そしてTry、例外処理の頭痛の種全体を自分で処理したくないが、それでも例外に満足しているコードとインターフェースする必要がある場合。

ちなみに、例外は良い例になります-したがって、他の場所よりも教科書や学習教材でそれらを見つけることが多いと思います:教科書の例は非常に不完全であることが非常に多いので、通常は注意深い設計によって防止される深刻な問題が必要です代わりに、例外をスローしてフラグを立てます。

*編集:SegfaultsはJVMをクラッシュさせ、バイトコードに関係なく発生することはありません。例外でさえあなたを助けません。私はスタックオーバーフローを意味しました。

**編集:例外(スタックトレースなし)は、Scalaの制御フローにも使用されます。これらは実際には非常に効率的なメカニズムであり、ライブラリ定義のbreakステートメントやreturn、制御が制御されていてもメソッドから返されるものなどを有効にします。実際に1つ以上のクロージャに渡されました。ほとんどの場合、これらの制御フローの例外の1つを誤ってキャッチする可能性があるため、すべて Throwableをキャッチすることはそれほど優れたアイデアではないことを理解することを除いて、これについて自分で心配する必要はありません。

于 2012-10-14T21:00:04.700 に答える
12

つまり、これは、Scalaが機能の純粋さを、レガシー言語や環境、特にJavaとの移行の容易さ/相互運用性とトレードオフする場所の1つです。機能の純度は、参照整合性を破り、等式的に推論することを不可能にするため、例外によって破られます。(もちろん、非終了再帰も同じですが、それらを不可能にする制限を強制する言語はほとんどありません。)機能の純粋さを維持するには、Option / Maybe / Either / Try / Validationを使用します。これらはすべて、成功をエンコードします。または参照透過型としての失敗、およびそれらが提供するさまざまな高階関数または基礎となる言語の特別なモナド構文を使用して、物事をより明確にします。または、Scalaでは、機能的な純度を捨てることを簡単に決めることができます。短期的には簡単になるかもしれませんが、長期的にはもっと難しくなるかもしれないことを知っています。これは、Scala、可変コレクション、またはローカルの「var」で「null」を使用するのと似ています。少し恥ずかしいです、そしてそれの多くをしません、しかし皆は締め切りの下にあります。

于 2012-10-14T22:36:40.663 に答える