scala 尝试和两者都不同有什么不同?

omhiaaxx  于 2022-11-09  发布在  Scala
关注(0)|答案(6)|浏览(169)

根据文件:
Try类型表示可能导致异常或返回成功计算值的计算。它与scala.util.任一类型相似,但在语义上不同。
这些文档没有进一步详细说明语义差异是什么。两者似乎都能交流成功和失败。你为什么要用一个而不是另一个呢?

q8l4jmvw

q8l4jmvw1#

在这个答案中,我讨论了TryEitherOption之间的关系。关于TryEither之间关系的要点总结如下:
Try[A]Either[Throwable, A]同构。换句话说,您可以将Try视为左侧类型为ThrowableEither,并且可以将左侧类型为Throwable的任何Either视为Try。通常使用Left表示失败,使用Right表示成功。
当然,您也可以更广泛地使用Either,而不仅仅是在缺少或异常值的情况下。在其他情况下,Either可以帮助表达简单联合类型的语义(其中,值是两种类型之一)。
从语义上讲,您可以使用Try来表示操作可能失败。在这种情况下,您可以类似地使用Either,特别是如果您的“错误”类型不是Throwable(例如,Either[ErrorType, SuccessType])。然后,当您在联合类型(例如Either[PossibleType1, PossibleType2])上操作时,也可以使用Either
从Scala 2.12开始,标准库确实包含从EitherTry或从TryEither的转换。对于早期版本,根据需要丰富TryEither非常简单:

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(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)
rlcwz9us

rlcwz9us2#

狭隘地回答你的问题:“语义有什么不同*”:
这可能指的是Flat Map和MAP,它们在任何一个中都不存在,并且要么传播失败,要么MapTry中的Success值。例如,这允许如下链接

for { 
   a <- Try {something} 
   b <- Try {somethingElse(a)}
   c <- Try {theOtherThing(b)}
} yield c

它所做的正是您所希望的--返回包含第一个异常或结果的尝试。
Try有很多其他有用的方法,当然还有它的配套应用方法,这使得它的预期用途非常方便-异常处理。
如果您真的想不知所措,还有另外两个类可能会对这种应用程序感兴趣。Scalaz有一个名为“/”(以前称为Prince)的类,发音为“any”,这与两者中的任何一个都很相似,但Flat Map和map的值都是正确的。同样地,Scalactic有一个“Or”,它也类似于两者中的任何一个,但flatMap和map在左边的值上工作。
我不推荐初学者使用Scalaz。

prdp8dxp

prdp8dxp3#

Either并不意味着成功和失败,它只是A或B的容器。用它来表示成功和失败是很常见的,惯例是把失败放在左边,把成功放在右边。
可以将Try视为左侧类型设置为ThrowableEitherTry[A]等同于Either[Throwable, A]
使用Try清楚地标识计算中的潜在故障,该故障由异常表示。如果希望用不同的类型(如字符串或一组扩展密封特征的案例类)表示故障,请使用Either

j91ykkif

j91ykkif4#

Either更通用,因为它只是表示类型的不相交的联合。具体地说,它可以表示某个类型的XException的有效返回值的并集。但是,它不会尝试自己捕获任何异常。您必须在危险代码周围添加try-Catch块,然后确保每个分支返回适当的Either子类(通常:Left表示错误,Right表示计算成功)。
Try[X]可以被认为是Either[Exception, X],但它本身也捕获异常。

1bqhqjot

1bqhqjot5#

Either[X, Y]的用法更一般。顾名思义,它既可以表示X类型的对象,也可以表示Y类型的对象。
Try[X]只有一种类型,它可能是成功的[X],也可能是失败的(包含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
}
dly7yett

dly7yett6#

如前所述,Either更通用,因此它不仅可以 Package 错误/成功结果,还可以用作Option的替代,用于分支代码路径。
为了抽象错误的影响,仅出于这个目的,我确定了以下区别:
1.Either可以用来指定错误的描述,并可以展示给客户端。Try-使用堆栈跟踪 Package 异常,较少描述性,较少面向客户端,更多地用于内部使用。
1.Either允许我们指定错误类型,现有的monoid用于指定该类型。因此,它允许我们组合错误(通常通过应用效果)。Try抽象及其异常未定义monoid。对于Try,我们必须花费更多的精力来提取错误并处理它。
基于此,以下是我的最佳实践:当我想抽象错误的影响时,我总是使用Either作为第一选择,使用List/Vector/NonEmptyList作为错误类型。
只有在调用用OOP编写的代码时才使用TryTry很好的候选方法是可能抛出异常的方法,或者向外部系统发送请求的方法(如果方法返回原始结果,则为REST/SOAP/数据库请求),而不是 Package 到FP抽象中,例如Future

相关问题