Scala pattern matching (try, try)

I have the following Tuple - (t1, t2): (Try, Try)

I want to check if both failed, or if one of them failed, but avoid code duplication. Sort of:

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

Of course, the 2nd operator will not work, since I need to provide different extraction parameters. but then I have to check them out, since I don’t know what failed and actually contains Throwable. I would like Try to act like Future, so it will have Try.sequence (t1, t2).

Any idea how to make this work elegantly?

+6
source share
4 answers

You can make a tail recursive call for the case (_, 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 lets you do it elegantly. For any F[_]: Traverse and G[_]: Applicative it defines the equivalent of Future.sequence :

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

The library also provides window instances for Try . Further reading in the workaround .

+3
source

You can convert it to Try[MyClass] as follows:

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

If t1 fails or t1 and t2 fail, either myclass will myclass with an Exception for t1 . If only t2 failed, myclass will myclass with an Exception for t2 . Otherwise, myclass will be Success . Then you can process it using recover or something else.

+6
source

You can extract the local method:

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

I would prefer the first OlivierBlanvillain sentence simply because it was easier to see that you cannot get an infinite loop.

+4
source

Instead of using Try, why not use Scalactic Or and Every ? So you can write something like this

 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: I am not associated with the library.

+2
source

Source: https://habr.com/ru/post/1015497/


All Articles