失败快捷功能链接
问题描述:
不知道是否有实现的功能链接上Any
如果遇到APIException
对象,将停止链更好的技术(不必延长Throwable
或Exception
,或使用throw
)。此外,宁愿不使用scalaz
(让我目瞪口呆)失败快捷功能链接
- 链接功能应进行
APIException
进行到底,并将其返回。 - 链接功能不必携带中间结果结束时,除了从最后一个块的输出。
下面是测试规范:
class FailFastChainSpec extends PlaySpec {
import utils.Ops._
def fFailsValidation(): Option[APIException] = Some(UnknownException())
def fPassesValidation(): Option[APIException] = None
def someCalculation = "Results"
"Utils" when {
"FailFastChaining" must {
"return Left(APIException) when encountered (at beginning of chain)" in {
fFailsValidation |> {
someCalculation
} mustBe Left(UnknownException())
}
"return Right(...) when no APIExceptions are encountered" in {
fPassesValidation |> {
someCalculation
} mustBe Right(someCalculation)
}
"return Left(APIException) when encountered (in middle of chain with 1 link)" in {
fPassesValidation |> fFailsValidation mustBe Left(UnknownException())
}
"return Left(APIException) when encountered (at end of chain with 1 link)" in {
fPassesValidation |> {
Left(UnknownException())
} mustBe Left(UnknownException())
}
"return Left(APIException) when encountered (at end of chain with 2 links)" in {
fPassesValidation |> fPassesValidation |> {
Left(UnknownException())
} mustBe Left(UnknownException())
}
"return Right(...) when no APIExceptions are encountered (multiple links)" in {
fPassesValidation |> fPassesValidation |> fPassesValidation |> fPassesValidation |> {
Right(someCalculation)
} mustBe Right(someCalculation)
}
"return Right(...) when no APIExceptions are encountered (complex multiple links)" in {
fPassesValidation |> fPassesValidation |> {
Right("Cupcakes")
} |> fPassesValidation |> {
Right(someCalculation)
} mustBe Right(someCalculation)
}
}
}
}
这里是我想出了,找这个改进的实现。
object Ops {
implicit def anyToAny[A](o: A): AnyOps[A] = new AnyOps[A](o)
class AnyOps[A](val a: A) {
def chain[B, C, D](c: C): Either[B, D] = |>[B,C,D](c)
def |>[B, C, D](c: C): Either[B, D] = {
a match {
case Some(v: APIException) => Left(v.asInstanceOf[B])
case v: APIException => Left(v.asInstanceOf[B])
case Left(v) => Left(v.asInstanceOf[B])
case _ => c match {
case Some(v: APIException) => Left(v.asInstanceOf[B])
case v: APIException => Left(v.asInstanceOf[B])
case Left(v) => Left(v.asInstanceOf[B])
case Right(v) => Right(v.asInstanceOf[D])
case v => Right(v.asInstanceOf[D])
}
}
}
}
}
答
如果用结合Option
类型的理解,那么你可以模拟一元的行为:
import scala.util.control.Exception._
import scala.util._
def dangerousOp = throw new RuntimeException("never works")
def f1(s: Int): Try[Int] = Success(s * 10)
def f2(s: Int): Try[Int] = catching(classOf[Exception]) toTry dangerousOp
def f3(s: Int): Try[Int] = Success(s * 30)
val result = for {
x <- f1(10)
y <- f2(x)
z <- f3(y)
} yield z
println(result) // Failure(java.lang.RuntimeException: never works)
如果其中任何失败与无,没有人会传播到产量。
编辑:实例方法f2
现在抛出一个异常,说明如何将其集成到这条产业链。也改为尝试使它更像你的例子。