2017-03-05 74 views
6

我有以下的元組 - (T1,T2):(試,試)Scala的模式匹配上(試,試)

我要檢查,如果兩者成功,或者如果他們中的一個失敗,但要避免代碼重複。例如:

(t1,t2) match { 
case (Success(v1),Success(v2)) => new MyClass(v1,v2) 
case (Failure(e),_) | (_,Failure(e)) => println(e.getMessage) 
} 

當然,第二條語句不起作用,因爲我需要給出不同的提取變量。但之後我必須檢查它們,因爲我不知道哪個失敗並且實際上包含Throwable。 我希望Try會像Future一樣行動,所以它會有Try.sequence(t1,t2)。

任何想法如何使這項工作優雅?

回答

3

你可以做的(_, Failure(e))情況下,尾遞歸調用:

@annotation.tailrec 
def apply(t1: Try[Any], t2: Try[Any]): Any = 
    (t1, t2) match { 
    case (Success(v1), Success(v2)) => new MyClass(v1,v2) 
    case (Failure(e), _) => println(e.getMessage) 
    case _ => apply(t2, t1) 
    } 

Cats可以讓你做到這一點優雅。對於任何F[_]: TraverseG[_]: Applicative,它定義的Future.sequence的equivalant:

def sequence(fa: F[G[A]]): G[F[A]] 

庫還提供out of the box instances for Try。進一步閱讀traverse documentation

+0

真棒圖書館,謝謝! – Raytracer

4

您可以提取本地方法:

def onFail(e: Throwable) = println(e.getMessage) 

(t1,t2) match { 
    case (Success(v1),Success(v2)) => new MyClass(v1,v2) 
    case (Failure(e),_) => onFail(e) 
    case (_,Failure(e)) => onFail(e) 
} 

我就喜歡OlivierBlanvillain的第一個建議,只是因爲它更容易看到你不能得到一個無限循環。

2

不使用Try,爲什麼不使用Scalactic Or and Every? 所以,你可以寫這樣的事情

val o1 = Or.from(t1) 
val o2 = Or.from(t2) 
withGood(o1, o2){(x, y) => { 
    //do what you want to do if both are good (or Success in Try) 
}}.recover{ 
    //do what you want to do if either one is bad (or Failure in Try) 
} 

PS:我不是與庫關聯。

6

你可以將它轉換爲Try[MyClass]這樣的:

val myclass = for { 
    v1 <- t1 
    v2 <- t2 
} yield new MyClass(v1, v2) 

如果t1失敗,或兩者t1t2失敗,myclass將是一個FailureExceptiont1。如果只有t2失敗,myclass將爲FailureExceptiont2。否則,myclass將是Success。然後,您可以使用recover或其他任何方式正常處理它。