Either、Option、Tryをソースレベルで理解
5137 ワード
差異 Either
結果の2つの可能性を表し、1つは Option
選択可能な値を表し、1つは Try
演算の結果、2つのケースがあり、1つは正常に動作している、すなわち
共通点
3つとも2つの可能性の値がある.いずれも結果の上で Either
ただし、ガード式の使用はサポートされていません.
同様に、以下もサポートされていません Option
対
もう一つの習慣的な使い方は(あまりお勧めしません)パターンマッチングです. Try
以上の例では、
結果の2つの可能性を表し、1つは
Right
、1つはLeft
選択可能な値を表し、1つは
Some
(値を表す)、1つはNone
(値が空).結果がnull
の場合によく用いられる.演算の結果、2つのケースがあり、1つは正常に動作している、すなわち
Success
、1つは運転エラー、異常放出、すなわちFailure
であり、そのうちFailure
には異常の情報が含まれている.共通点
3つとも2つの可能性の値がある.いずれも結果の上で
map
・flatMap
などの操作が可能である.Right
とLeft
は、Either
から継承された2つcase
クラスである. //Left
final case class Left[+A, +B](@deprecatedName('a, "2.12.0") value: A) extends Either[A, B]
//Right
final case class Right[+A, +B](@deprecatedName('b, "2.12.0") value: B) extends Either[A, B]
Eihter
1つの結果の2つの可能性を表し、1つはRight
、1つはLeft
; import scala.io.StdIn._
val in = readLine("Type Either a string or an Int: ")
val result: Either[String,Int] =
try Right(in.toInt)
catch {
case e: NumberFormatException => Left(in)
}
result match {
case Right(x) => s"You passed me the Int: $x, which I will increment. $x + 1 = ${x+1}"
case Left(x) => s"You passed me the String: $x"
}
Either
偏っているRight
値の場合、Either
使用map
・flatMap
等の操作の場合、Either
の結果Right
の場合のみ、操作がトリガーされる.習慣的にLeft
値は悪い結果(失敗した結果)、Right
良い結果(成功した結果)を表す. def doubled(i: Int) = i * 2
Right(42).map(doubled) // Right(84)
Left(42).map(doubled) // Left(42)
Either
定義したflatMap
とmap
のため、Either
に対して使用可能for comprehensions
; val right1 = Right(1) : Right[Double, Int] // right1
val right2 = Right(2)
val right3 = Right(3)
val left23 = Left(23.0) : Left[Double, Int] // left23
val left42 = Left(42.0)
for {
x
ただし、ガード式の使用はサポートされていません.
for {
i 0
} yield i
// error: value withFilter is not a member of Right[Double,Int]
同様に、以下もサポートされていません
for (x: Int
for comprehensions
使用map
およびflatMap
のため、パラメータのタイプを導出しなければならず、このタイプはEither
でなければならない.特に、Either
偏向Right
のため、Either
に対する値はLeft
そのタイプを指定しなければならないが、そうでなければ、その位置のデフォルトタイプはNothing
である. for {
x
Some
とNone
は、Option
から継承された2つcase
クラスである. //Some
final case class Some[+A](@deprecatedName('x, "2.12.0") value: A) extends Option[A]
//None
case object None extends Option[Nothing]
対
Option
の慣用としては集合とするかmonad
、通過map
・flatMap
・filter
・・とforeach
: //
val name: Option[String] = request getParameter "name"
val upper = name map { _.trim } filter { _.length != 0 } map { _.toUpperCase }
println(upper getOrElse "")
//
val upper = for {
name
もう一つの習慣的な使い方は(あまりお勧めしません)パターンマッチングです.
val nameMaybe = request getParameter "name"
nameMaybe match {
case Some(name) =>
println(name.trim.toUppercase)
case None =>
println("No name value")
}
Failure
とSuccess
は、Try
から継承された2つcase
クラスである. //Failure
final case class Failure[+T](exception: Throwable) extends Try[T]
//Success
final case class Success[+T](value: T) extends Try[T]
Try
異常がある場合によく用いられ、Try
発生する可能性のある異常を不確定に処理する. import scala.io.StdIn
import scala.util.{Try, Success, Failure}
def divide: Try[Int] = {
val dividend = Try(StdIn.readLine("Enter an Int that you'd like to divide:
").toInt)
val divisor = Try(StdIn.readLine("Enter an Int that you'd like to divide by:
").toInt)
val problem = dividend.flatMap(x => divisor.map(y => x/y))
problem match {
case Success(v) =>
println("Result of " + dividend.get + "/"+ divisor.get +" is: " + v)
Success(v)
case Failure(e) =>
println("You must've divided by zero or entered something that's not an Int. Try again!")
println("Info from the exception: " + e.getMessage)
divide
}
}
以上の例では、
Try
の重要な特性の一つとして、Try
配管機能を有すること、flatMap
およびmap
それらの成功した操作の結果をSuccess
に包装し、それらの異常をFailure
に包装し、recover
およびrecoverWith
に対しては、デフォルト対Failure
結果がトリガーされることが分かる.