2015-02-10 48 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現在拋出一個異常,說明如何將其集成到這條產業鏈。也改爲嘗試使它更像你的例子。