2011-12-16 11 views
0

私はScala Option[T]を持っています。値がSome(x)の場合、値(Unit)を返さないプロセスで処理したいのですが、Noneの場合はエラーを出力します。Scalaオプションの処理[T]

私はこれをどのように行うのですかなど、私はこれを行うには、次のコードを使用することができますが、私はより多くの慣用的な方法は、シーケンスとしてOption[T]を扱い、mapを使用することであることを理解し、foreach

opt match { 
    case Some(x) => // process x with no return value, e.g. write x to a file 
    case None => // print error message 
} 
+3

[Tony Morris 'scala.Option Cheat Sheet](http://blog.tmorris.net/scalaoption-cheat-sheet/)をご覧ください。 –

+0

リンクがhttp://blog.tmorrisに変更されました.net/posts/scalaoption-cheat-sheet/index.html – giampaolo

答えて

3

ScalaのOptionは、まさにこれを行うための方法を逃し、悲しいこと、です。私は1つを追加します(私の見解では)少しよりよいがあり

class OptionWrapper[A](o: Option[A]) { 
    def fold[Z](default: => Z)(action: A => Z) = o.map(action).getOrElse(default) 
} 
implicit def option_has_utility[A](o: Option[A]) = new OptionWrapper(o) 

使い方

op.fold{ println("Empty!") }{ x => doStuffWith(x) } 

あなたはmap/getOrElseではなく、パターンマッチングを使用することができることが規定されていますどのように見ることができます。

また、Eitherはすでにfoldメソッドを持っています。だから、

op.toRight(()).fold{ _ => println("Empty!") }{ x => doStuffWith(x) } 

をすることができますが、これは、あなたが左の価値を提供する(ここでは()、すなわち単位)と、その上の関数を定義だけではなく、あなたが起こるしたいものを伝えるために持っていることを考えると少し不器用ですNone

パターンマッチは、特にコードの長いブロックの場合にも悪くありません。短いものについては、試合のオーバーヘッドがポイントの途中で始まります。たとえば:

op.fold{ printError }{ saveUserInput } 

op match { 
    case Some(x) => saveUserInput(x) 
    case None => printError 
} 

よりもはるかに少ない構文のオーバーヘッドを持っており、あなたはそれを期待したらそれゆえ、理解するずっと簡単です。

3

私は単純かつ安全optNoneであれば、それ自体がNoSuchElementException例外をスローopt.getを使用することをお勧めします。それとも、独自の例外をスローする場合、あなたはこれを行うことができます。

val x = opt.getOrElse(throw new Exception("Your error message")) 
// x is of type T 
+0

私はエラーメッセージを投げたくありません。 std errにエラーを出力するだけです。私はtry-catchですべてを包み込むことができると思うが、それは過剰なもののようだ。 – Ralph

+0

はい、try-catchが最適な戦略です。ファイル書き込みに関するすべてのコードをtryブロックにラップするか、いくつかの方法でそれをよりよく取り除くことができます。また、私の答えの更新を書き留めておいてください。 –

6

私は、明示的なパターンマッチングが最良のあなたのユースケースに合うと思います。

+0

私はRex Kerrの答えを実際には私が尋ねた質問に答えたので選択しましたが、読みやすさのためにパターンマッチングが勝ちます。特に、Scalaに慣れていない人がコードを読む必要がある。 +1 – Ralph

+0

@Ralph:読みやすさ、親しみやすさなどは、私がパターンマッチングを提案したときに気にしたことではありません。私は一般に、より高次のコンビネータを明示的なパターンマッチングに優先します。そのIMOは、(そのコンビネータが何をするかを知っていれば)読みやすさ、簡潔さ、そしてもちろん合成可能性につながります。 '.fold'または' .cata'のコンビネータはあなたのユースケースに対応しますが、それぞれのケースに対して実行するコードの2つの意味のない(読みやすい)ブロックがあります。したがって、コンビネータオーバーパターンマッチングを使用しても、読みやすさや簡潔さの面でそれで私の提案。 – missingfaktor

2

ここでパターンマッチングが最適です。あなたはシーケンスとしてオプションを治療し、単位が値であるので、あなたがそれを行うことができ、その上にマップしたい場合は

しかし、:エラーを印刷ところで

opt map { v => 
    println(v) // process v (result type is Unit) 
} getOrElse { 
    println("error") 
} 

、いくつかの種類のは、 「アンチパターン」、それがとにかく例外をスローすることをお勧めですので:

opt.getOrElse(throw new SomeException) 
+2

私は、テキストファイルにリストされた数百万のファイルをトラバースし、それらのためのコピーコマンドを生成する非常に簡単なユーティリティを書いています。ファイルが見つからないか、読み込めない場合は、小さなエラーメッセージを出力したいだけです。コピーコマンドはstdoutに、エラーはstderrに送られます。 – Ralph

2

@missingfaktorを使用すると、パターンマッチングが最も読みやすい結果を与えている正確なシナリオであり、言うように。 Optionに何かしたい値があれば、そうでない場合は何か他のことをしたい。

オプションタイプにマップし、他の機能構造を使用するための様々な方法がありますがとき、彼らは一般的に便利です:

はあなたには、いくつかのケースを使用して、例えばなしケースを無視したいですあなたのケース

opt.map(writeToFile(_)) //(...if None just do nothing) 

かであなたがチェーンに複数のオプションの操作をしたいし、それらのすべてがいくつかある場合にのみ、結果を与えます。たとえば、これを行うための一つの方法は次のとおりです。

val concatThreeOptions = 
for { 
    n1 <- opt1 
    n2 <- opt2 
    n3 <- opt3 
} yield n1 + n2 + n3 // this will be None if any of the three is None 
        // we will either write them all to a file or none of them 

が、これらのどれもが、あなたのケースのように見えるん

関連する問題