エラー処理によるコードの分岐を減らしたい場合、Eitherを使うとよい。
Either[A, B]
は、A
またはB
を返す型である。
Eitherは通常Either[(エラー情報), (結果)]
の形で使われる。例えばデータ処理が成功した場合はその結果を用いて引き続きの処理を行いたいが、エラーの場合は何もせず次のコードにエラーだけを伝えたい場合がある。
Eitherから値を取り出すには、left, rightの値に対してmap, flatMapなどを用いる。例えば、Either.right map { ... }
とすると、値の内容がRight
型の場合はmap内の関数を適用し、Left
の型の場合はmapの処理を無視してLeft
の内容(この場合はエラー情報を)をそのまま返す。
# 文字列がIntに変換できるならIntを、失敗した場合はExceptionを返す関数
scala> def parseInt(s:String) : Either[Exception, Int] =
try Right(s.toInt) catch { case e:Exception => Left(e) }
Parseint: (s: String)Either[Exception,Int]
# Intへの変換が成功。Rightを返す
scala> parseInt("128")
res5: Either[Exception,Int] = Right(128)
# 変換できない場合はLeftを返す
scala> parseInt("234A")
res6: Either[Exception,Int] = Left(java.lang.NumberFormatException: For input string: "234A")
# 値を取りだしてFloatに変換
scala> parseInt("49").right map { _.toFloat }
res8: Product with Serializable with Either[Exception,Float] = Right(49.0)
# 結果がLeft(Exception)の場合は、toFloatは実行されずに、Exceptionを伝播する
scala> parseInt("ADF").right map { _.toFloat }
res9: Product with Serializable with Either[Exception,Float] = Left(java.lang.NumberFormatException: For input string: "ADF")
# Left(Exception)であれば、その内容を表示(getMessage)
scala> parseInt("ADF").left map { _.getMessage }
res11: Product with Serializable with Either[java.lang.String,Int] = Left(For input string: "ADF")
# 結果がRightの場合は、getMessageは実行されない
scala> parseInt("40").left map { _.getMessage }
res12: Product with Serializable with Either[java.lang.String,Int] = Right(40)
Eitherを使うことで、エラーを含んだデータであっても処理の流れを妨げないようにできる。