Scala学習【エラー処理に使う型】

前回に引き続きScalaの学習。今回はエラー処理で使うであろう戻り値をラップする型について。

Option型

  • 値をひとつだけ入れることができる
  • 2種類の形を持っている
    • Some(x) 値があるときの形
    • None 値がないときの形
  • 値があったりなかったりする値を表現するときに使う
  • エラー内容を表現できないので、エラー処理では使わない
// Some: 値があるとき
scala> val some: Option[String] = Option("hoge")
some: Option[String] = Some(hoge)

scala> some.get
res7: String = hoge

// None: 値がないとき
scala> val none: Option[String] = Option(null)
none: Option[String] = None

scala> none.get
java.util.NoSuchElementException: None.get
  at scala.None$.get(Option.scala:349)
  at scala.None$.get(Option.scala:347)
  ... 29 elided

Noneget したときの例外は getOrElse メソッドを使えば回避できる

scala> option.getOrElse("値がありません")
res3: String = 値がありません

パターンマッチを使って処理することもできる

scala> val some: Option[String] = Option("hoge")
some: Option[String] = Some(hoge)

scala> some match {
     |   case Some(str) => println(str) // Someの中身をstrという変数に束縛している
     |   case None => print("None")
     | }
hoge

Optionはコレクションの性質を持っているので、例えばmapを使える

// Some の場合
scala> Some(3).map(_ * 3)
res10: Option[Int] = Some(9)


// None の場合は関数を適用しても None のまま
scala> val none: Option[Int] = None
none: Option[Int] = None

scala> none.map(_ * 3)
res11: Option[Int] = None

// foldメソッドを使えばデフォルト値を指定できる
scala> none.fold(0)(_ * 3)
res12: Int = 0

Either型

  • Option型と違い、エラー時に任意のエラーの種類まで取得できる
  • RightとLeftの2つの値を持つ
    • Right: 正常な値
    • Left: エラー値
scala> val right: Either[String, Int] = Right(123)
right: Either[String,Int] = Right(123)

scala> val left: Either[String, Int] = Left("abc")
left: Either[String,Int] = Left(abc)

// パターンマッチもできる
scala> right match {
     |    case Right(i) => println(i)
     |    case Left(s)  => println(s)
     | }
123

Option型と同様にmapメソッドを持っている Either型の左右が平等に扱われる場合、mapメソッドはどちらに適用されるのだろう。となるが、暗黙的にrightを優先される(Scala2.12から) Scala2.12より前は平等に扱われるため、RightProjection型に変換する必要があった

// サジェストされるメソッドを確認
scala> right.
canEqual   filterOrElse   forall      isLeft     joinRight   merge            productIterator   swap       toTry
contains   flatMap        foreach     isRight    left        productArity     productPrefix     toOption
exists     fold           getOrElse   joinLeft   map         productElement   right             toSeq

// Scala2.12
scala> right.map(_ * 3)
res0: scala.util.Either[String,Int] = Right(369)

// Scala2.12より前
scala> right.right
res1: scala.util.Either.RightProjection[String,Int] = RightProjection(Right(123))

scala> right.right.map(_ * 3)
res0: scala.util.Either[String,Int] = Right(369)

Try型

  • 2つの値をとる
    • Success: 正常な値
    • Failure: エラー値(ただしThrowableというExceptionスーパークラスしか入れられない)
  • applyで生成する際に例外をキャッチし、Failureにする
  • NonFatal(致命的でない)という種類の例外だけキャッチする
scala> import scala.util.Try
import scala.util.Try

scala> val failure: Try[Int] = Try(throw new RuntimeException("to be caught"))
failure: scala.util.Try[Int] = Failure(java.lang.RuntimeException: to be caught)

scala> val success = Try(3)
success: scala.util.Try[Int] = Success(3)

参考

Scalaスケーラブルプログラミング第3版 - インプレスブックス

N予備校 プログラミングコース