Try类型表示可能导致a的计算 异常,或返回成功计算的值。它类似于, 但语义上与scala.util.Either类型不同。
文档没有详细说明语义差异是什么。两者似乎都能够传达成功和失败。你为什么要用一个呢?
答案 0 :(得分:33)
我介绍了this answer中Try
,Either
和Option
之间的关系。关于Try
和Either
之间关系的重点摘要如下:
Try[A]
与Either[Throwable, A]
同构。换句话说,您可以将Try
视为Either
,其左侧类型为Throwable
,您可以处理左侧类型为Either
的任何Throwable
}作为Try
。通常使用Left
表示失败,Right
表示成功。
当然,您也可以更广泛地使用Either
,不仅适用于缺失值或特殊值的情况。还有其他情况Either
可以帮助表达简单联合类型的语义(其中value是两种类型之一)。
从语义上讲,您可以使用Try
来指示操作可能会失败。在这种情况下,您可能会同样使用Either
,特别是如果您的错误"}类型不是Throwable
(例如Either[ErrorType, SuccessType]
)。然后,当您对联合类型(例如Either
)进行操作时,您也可以使用Either[PossibleType1, PossibleType2]
。
标准库不包含从Either
到Try
或从Try
到Either
的转化,但丰富Try
非常简单,和Either
根据需要:
object TryEitherConversions {
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
}
}
这将允许你这样做:
import TryEitherConversions._
//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)
答案 1 :(得分:10)
要简单回答你的问题:“语义差异是什么”:
这可能是指flatMap和map,它们在Either中不存在,并且传播失败或映射Try中的成功值。例如,这允许链接像
for {
a <- Try {something}
b <- Try {somethingElse(a)}
c <- Try {theOtherThing(b)}
} yield c
这正是您所希望的 - 返回包含第一个异常或结果的Try。
尝试有许多其他有用的方法,当然还有它的伴随应用方法,使其非常方便其预期用途 - 异常处理。
如果你真的想要被淹没,那么还有另外两个类可能对这种应用感兴趣。 Scalaz有一个名为“\/”(以前称为Prince)的类,发音为“Either”,其大部分类似于Either,但flatMap和map在Right值上工作。类似地,而不是,Scalactic有一个“Or”,它也类似于Either,但是flatMap和map在Left值上工作。
我不建议初学者使用Scalaz。
答案 2 :(得分:3)
Either
并不意味着成功和失败,它只是A或B的容器。通常用它来表示成功和失败,惯例是将失败放在左边一边,右边的成功。
Try
可以看作是Either
,左侧类型设置为Throwable
。 Try[A]
等同于Either[Throwable, A]
。
使用Try
清楚地识别计算中的潜在故障,故障由异常表示。如果您想用不同的类型表示失败(例如String或一组扩展密封特征的案例类),请使用Either
。
答案 3 :(得分:1)
Either
更为通用,因为它只代表不相交的类型联盟。
特别是,它可以表示某种类型X
和Exception
的有效返回值的并集。但是,它并不试图自己捕获任何异常。您必须在危险代码周围添加try-catch块,然后确保每个分支返回Either
的适当子类(通常:Left
表示错误,Right
表示成功计算)。
Try[X]
可以被视为Either[Exception, X]
,但它也可以自行捕获异常。
答案 4 :(得分:1)
Either[X, Y]
用法更为一般。顾名思义它可以代表X型或Y型的对象。
Try[X]
只有一种类型,可能是Success [X]或Failure(包含Throwable
)。
在某些时候,您可能会将Try[X]
视为Either[Throwable,X]
Try[X]
的好处是你可以将更多的操作链接到它,如果它真的是一个成功他们将执行,如果它是一个失败他们将不会
val connection = Try(factory.open())
val data = connection.flatMap(conn => Try(conn.readData()))
//At some point you can do
data matches {
Success(data) => print data
Failure(throwable) => log error
}
当然,你可以像
一样直播Try(factory.open()).flatMap(conn => Try(conn.readData()) matches {
Success(data) => print data
Failure(throwable) => log error
}
答案 5 :(得分:0)
正如已经提到的,Either
更通用,因此它不仅可以包装错误/成功的结果,还可以用作Option
的替代品,以分支代码路径。
为抽象错误的影响,仅出于此目的,我确定了以下差异:
Either
可用于指定错误的描述,该描述可显示给客户端。 Try
-用堆栈跟踪包装一个异常,该异常具有较少的描述性,较少的面向客户端的用途,更多地用于内部使用。 Either
允许我们使用现有的monoid
来指定错误类型。结果,它使我们能够合并错误(通常是通过应用效果)。 Try
抽象没有定义,没有定义monoid
。使用Try
,我们必须花更多的精力来提取错误并进行处理。
基于此,这是我的最佳做法:
当我想抽象错误的效果时,我总是以Either
/ List
/ Vector
作为错误类型为第一选择。
NonEmptyList
仅在调用以OOP编写的代码时使用。 Try
的最佳候选方法是可能会引发异常的方法,或者是将请求发送到外部系统的方法(如果方法返回原始结果(未包装到FP抽象中,则是{rest / soap / database请求,例如{例如{1}}。