Either
をOption
と同様の方法で処理することは可能ですか? Option
にはgetOrElse
関数があり、Either
にはLeft
またはプロセスRight
を返したいです。私はこれのような定型文なしでこれを行う最速の方法を探しています:
val myEither:Either[String, Object] = Right(new Object())
myEither match {
case Left(leftValue) => value
case Right(righValue) =>
"Success"
}
Scala 2.12、
どちらかが右にバイアスされています。つまり、Rightが操作のデフォルトケースと見なされます。Leftの場合、map、flatMapなどの操作はLeft値を変更せずに返します
あなたができるので
myEither.map(_ => "Success").merge
fold
より読みやすい場合。
.fold
を使用できます。
scala> val r: Either[Int, String] = Right("hello")
r: Either[Int,String] = Right(hello)
scala> r.fold(_ => "got a left", _ => "Success")
res7: String = Success
scala> val l: Either[Int, String] = Left(1)
l: Either[Int,String] = Left(1)
scala> l.fold(_ => "got a left", _ => "Success")
res8: String = got a left
編集:
あなたの質問を読み直すと、Left
の値を返すのか、別の値(別の場所で定義)を返すのかがわかりません。
前者の場合、identity
を.fold
に渡すことができますが、これにより戻り値の型がAny
に変更される可能性があります。
scala> r.fold(identity, _ => "Success")
res9: Any = Success
CchantepとMarthはどちらも、当面の問題に対する優れたソリューションです。しかし、より広く言えば、EitherをOption
に完全に類似したものとして扱うことは、特に、理解のために失敗する可能性のある計算のシーケンスを表現できるようにする場合には困難です。どちらもプロジェクションAPI(cchantepのソリューションで使用)を持っていますが、少し壊れています。 (どちらの予測も、ガード、パターンマッチング、または変数の割り当てによる理解のために割り込んでいます。)
FWIW、私はこの問題を解決するために library を作成しました。 this API を使用して拡張します。 Eithersの「バイアス」を定義します。 「正しいバイアス」とは、通常のフロー(map、getなど)がRight
オブジェクトによって表される一方で、Left
オブジェクトが何らかの問題を表すことを意味します。 (右バイアスは従来通りですが、必要に応じて左バイアスを定義することもできます。)次に、Either
をOption
のように扱うことができます。完全に類似したAPIを提供します。
_import com.mchange.leftright.BiasedEither
import BiasedEither.RightBias._
val myEither:Either[String, Object] = ...
val o = myEither.getOrElse( "Substitute" )
_
より便利に、Eitherをtrue scalaモナドのように扱うことができます。つまり、flatMap、map、filterを使用して、内包表記に使用できます。
_val myEither : Either[String, Point] = ???
val nextEither = myEither.map( _.x ) // Either[String,Int]
_
または
_val myEither : Either[String, Point] = ???
def findGalaxyAtPoint( p : Point ) : Either[String,Galaxy] = ???
val locPopPair : Either[String, (Point, Long)] = {
for {
p <- myEither
g <- findGalaxyAtPoint( p )
} yield {
(p, g.population)
}
}
_
すべての処理ステップが成功した場合、locPopPair
は_Right[Long]
_になります。問題が発生した場合は、最初に_Left[String]
_が発生します。
少し複雑ですが、空のトークンを定義することをお勧めします。上記の理解度のわずかな変化を見てみましょう:
_val locPopPair : Either[String, (Point, Long)] = {
for {
p <- myEither
g <- findGalaxyAtPoint( p ) if p.x > 1000
} yield {
(p, g.population)
}
}
_
テスト_p.x > 1000
_が失敗した場合はどうなりますか? 「空」を表すLeft
を返したいのですが、普遍的な適切な値はありません(すべてのLeft
が_Left[String]
_であるとは限りません。現在のところ、何が起こるかはコードはNoSuchElementException
をスローしますが、次のように自分で空のトークンを指定できます。
_import com.mchange.leftright.BiasedEither
val RightBias = BiasedEither.RightBias.withEmptyToken[String]("EMPTY")
import RightBias._
val myEither : Either[String, Point] = ???
def findGalaxyAtPoint( p : Point ) : Either[String,Galaxy] = ???
val locPopPair : Either[String, (Point, Long)] = {
for {
p <- myEither
g <- findGalaxyAtPoint( p ) if p.x > 1000
} yield {
(p, g.population)
}
}
_
これで、_p.x > 1000
_テストが失敗した場合、例外は発生せず、locPopPair
はLeft("EMPTY")
になります。
次のようにできると思います。
def foo(myEither: Either[String, Object]) =
myEither.right.map(rightValue => "Success")