@runzhliu
2018-05-30T12:14:19.000000Z
字数 2942
阅读 1215
scala either left right
转载整理 http://colobu.com/2015/06/11/Scala-Either-Left-And-Right/
Scala 中的 Either 是一个有趣的类,它代表两个可能的类型的其中一个类型的值。这两个值之间没有交集。
Either 是抽象类,有两个具体的实现类: Left 和 Right。
sealed abstract class Either[+A, +B] {/*** Projects this `Either` as a `Left`.*/def left = Either.LeftProjection(this)/*** Projects this `Either` as a `Right`.*/def right = Either.RightProjection(this)/*** Applies `fa` if this is a `Left` or `fb` if this is a `Right`.** @example {{{* val result: Either[Exception, Value] = possiblyFailingOperation()* log(result.fold(* ex => "Operation failed with " + ex,* v => "Operation produced value: " + v* ))* }}}** @param fa the function to apply if this is a `Left`* @param fb the function to apply if this is a `Right`* @return the results of applying the function*/def fold[X](fa: A => X, fb: B => X) = this match {case Left(a) => fa(a)case Right(b) => fb(b)}
Either 可以作为 scala.Option 的替换,可以用 scala.util.Left 替换 scala.None,用 scala.Right 替换 scala.Some。
一般在时实践中使用 scala.util.Left 作为 Failure,而 scala.util.Right 作为成功的值。另一个类似的类是 scala.util.Try,举个例子:
val in = Console.readLine("Type Either a string or an Int: ")val result: Either[String,Int] = try {Right(in.toInt)} catch {case e: Exception =>Left(in)}println( result match {case Right(x) => "You passed me the Int: " + x + ", which I will increment. " + x + " + 1 = " + (x+1)case Left(x) => "You passed me the String: " + x})
如果输入的值可以转换成 Int 类型,则结果 result 为 Right(int),否则 result 为 Left(String)。你可以使用 match 处理结果。Either 类型还提供了投影(projection)操作。根据类型是 Left 还是 Right 返回不同的结果。
例如,使用一个函数转换 Either 类型的值时,如果值是 Left,应用 left 投影,然后调用 map 返回处理的结果,而应用 right 投影只是返回 Left,如:
val l: Either[String, Int] = Left("flower")val r: Either[String, Int] = Right(12)l.left.map(_.size): Either[Int, Int] // Left(6)l.right.map(_.toDouble): Either[String, Double] // Left("flower")
同样地,对 Right 值进行 left 投影,只是返回 Right,不做改变,只会对 right 投影起作用:
val l: Either[String, Int] = Left("flower")val r: Either[String, Int] = Right(12)r.left.map(_.size): Either[Int, Int] // Right(12)r.right.map(_.toDouble): Either[String, Double] // Right(12.0)
既然定义了 map 操作,就可以使用 for 语句:
for (s <- l.left) yield s.size // Left(6)
Either 除了 left,right 投影外,还提供一些其它的方法:
fold: l.fold(x => x.size, y => y.toDouble);r.fold(x => x.size, y => y.toDouble)swap: l.swap //Right(flower)merge: l.merge == "flower"joinLeft: LeftEither[Int, String], String).joinLeftjoinRight: Either[A, Either[A, C]]
在 Scala 中使用 Future,经常会处理 Future 的最终结果,要不成功,要不失败,这里就使用了 Either:
val f: Future[List[String]] = future {session.getRecentPosts}f onComplete {case Right(posts) => for (post <- posts) render(post)case Left(t) => render("An error has occured: " + t.getMessage)}
前面提到 Try 也是两个值,Success 和 Failure,它可以和 Either 进行转换:
object Helper{implicit class EitherPimp[L <: Throwable,R](e:Either[L,R]){def toTry:Try[R] = e.fold(Failure(_), Success(_))}implicit class TryPimp[T](t:Try[T]){def toEither:Either[Throwable,T] = t.transform(s => Success(Right(s)), f => Success(Left(f))).get}}
或者
import scala.util.{ Either, Failure, Left, Right, Success, Try }implicit def eitherToTry[A <: Exception, B](either: Either[A, B]): Try[B] = {either match {case Right(obj) => Success(obj)case Left(err) => Failure(err)}}implicit def tryToEither[A](obj: Try[A]): Either[Throwable, A] = {obj match {case Success(something) => Right(something)case Failure(err) => Left(err)}
