2015-02-10 49 views
0

不知道是否有实现的功能链接上Any如果遇到APIException对象,将停止链更好的技术(不必延长ThrowableException,或使用throw)。此外,宁愿不使用scalaz(让我目瞪口呆)失败快捷功能链接

  1. 链接功能应进行APIException进行到底,并将其返回。
  2. 链接功能不必携带中间结果结束时,除了从最后一个块的输出。

下面是测试规范:

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]) 
     } 
     } 
    } 
    } 

} 

回答

0

如果用结合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现在抛出一个异常,说明如何将其集成到这条产业链。也改为尝试使它更像你的例子。