选项和选项之间有什么区别? [英] What are the differences between Either and Option?
问题描述
根据文档:
Either 的一个常见用途是作为 Option 的替代来进行交易可能存在缺失值.
A common use of Either is as an alternative to Option for dealing with possible missing values.
你为什么要使用一个?
推荐答案
Either
的好处在于您可以跟踪缺少某些东西的原因.例如,如果您使用 Options
,您可能会处于这样的情况:
The nice thing about Either
is that you can keep track of the reason something is missing. For example, if you were working with Options
, you might be in a situation like this:
val xOpt = Option(1)
val yOpt = Option(2)
val zOpt = None
val tupled = for {
x <- xOpt
y <- yOpt
z <- zOpt
} yield (x, y, z)
现在,如果 tupled
是 None
,我们真的不知道为什么!如果这是其余行为的重要细节,使用 Either
会有所帮助:
Now, if tupled
is None
, we don't really know why! If this is an important detail for the rest of the behavior, using Either
can help:
val tupled = for {
x <- xOpt.toRight("x is missing").right
y <- yOpt.toRight("y is missing").right
z <- zOpt.toRight("z is missing").right
} yield (x, y, z)
这将返回 Left(msg)
,其中消息是第一个缺失值的对应消息,或者 Right(value)
用于元组值.按照惯例,使用 Left
表示失败,使用 Right
表示成功.
This will return either Left(msg)
where the message is the first missing value's corresponding message, or Right(value)
for the tupled value. It is conventional to keep use Left
for failures and Right
for successes.
当然,您也可以更广泛地使用 Either
,而不仅仅是在值缺失或异常的情况下.在其他情况下,Either
可以帮助表达简单联合类型的语义.
Of course, you can also use Either
more broadly, not only in situations with missing or exceptional values. There are other situations where Either
can help express the semantics of a simple union type.
用于异常值的第三个常见习语是 Try
monad:
The third common idiom to use for exceptional values is the Try
monad:
val xTry = Try("1".toInt)
val yTry = Try("2".toInt)
val zTry = Try("asdf".toInt)
val tupled = for {
x <- xTry
y <- yTry
z <- zTry
} yield (x, y, z)
Try[A]
与 Either[Throwable, A]
同构.换句话说,您可以将 Try
视为具有左类型 Throwable
的 Either
,并且您可以将任何 Either
code> 的左类型为 Throwable
作为 Try
.此外,Option[A]
与 Try[A]
同态.因此,您可以将 Option
视为忽略错误的 Try
.因此,您也可以将其视为一个 Either
.事实上,标准库支持其中一些转换:
Try[A]
is isomorphic to Either[Throwable, A]
. In other words you can treat a Try
as an Either
with a left type of Throwable
, and you can treat any Either
that has a left type of Throwable
as a Try
. Also Option[A]
is homomorphic to Try[A]
. So you can treat an Option
as a Try
that ignores errors. Therefore you can also transitively think it as an Either
. In fact, the standard library supports some of these transformations:
//Either to Option
Left[Int, String](1).left.toOption //Some(1)
Right[Int, String]("foo").left.toOption //None
//Try to Option
Try("1".toInt).toOption //Some(1)
Try("foo".toInt).toOption //None
//Option to Either
Some(1).toRight("foo") //Right[String, Int](1)
(None: Option[Int]).toRight("foo") //Left[String, Int]("foo")
标准库不包括从 Either
到 Try
、从 Try
到 Either
的转换,或从 Option
到 Try
.但是根据需要丰富 Option
、Try
和 Either
非常简单:
The standard library does not include the conversions from Either
to Try
, from Try
to Either
, or from Option
to Try
. But it is pretty simple to enrich Option
, Try
, and Either
as needed:
object OptionTryEitherConversions {
implicit class EitherToTry[L <: Throwable, R](val e: Either[L, R]) extends AnyVal {
def toTry: Try[R] = e.fold(Failure(_), Success(_))
}
implicit class TryToEither[T](val t: Try[T]) extends AnyVal {
def toEither: Either[Throwable, T] = t.map(Right(_)).recover(PartialFunction(Left(_))).get
}
implicit class OptionToTry[T](val o: Option[T]) extends AnyVal {
def toTry(throwable: Throwable): Try[T] = o.map(Right(_)).getOrElse(Left(throwable))
}
}
这将允许您:
import OptionTryEitherConversions._
//Try to Either
Try(1).toEither //Either[Throwable, Int] = Right(1)
Try("foo".toInt).toEither //Either[Throwable, Int] = Left(java.lang.NumberFormatException)
//Either to Try
Right[Throwable, Int](1).toTry //Success(1)
Left[Throwable, Int](new Exception).toTry //Failure(java.lang.Exception)
//Option to Try
Some(1).toTry(new Exception) //Success(1)
(None: Option[Int]).toTry(new Exception) //Failure(java.lang.Exception)
这篇关于选项和选项之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!