Flatten Scala Try

后端 未结 7 1024
天命终不由人
天命终不由人 2020-12-14 19:20

Is there a simple way to flatten a collection of try\'s to give either a success of the try values, or just the failure? For example:

def map(l:List[Int]) =          


        
7条回答
  •  独厮守ぢ
    2020-12-14 20:19

    Maybe not as simple as you hoped for, but this works:

    def flatten[T](xs: Seq[Try[T]]): Try[Seq[T]] = {
      val (ss: Seq[Success[T]]@unchecked, fs: Seq[Failure[T]]@unchecked) =
        xs.partition(_.isSuccess)
    
      if (fs.isEmpty) Success(ss map (_.get))
      else Failure[Seq[T]](fs(0).exception) // Only keep the first failure
    }
    
    val xs = List(1,2,3,4,5,6)
    val ys = List(1,2,3,5,6)
    
    println(flatten(map(xs))) // Failure(java.lang.Exception: failed)
    println(flatten(map(ys))) // Success(List(1, 2, 3, 5, 6))
    

    Note that the use of partition is not as type safe as it gets, as witnessed by the @unchecked annotations. In that respect, a foldLeft that accumulates two sequences Seq[Success[T]] and Seq[Failure[T]] would be better.

    If you wanted to keep all failures, you can use this:

    def flatten2[T](xs: Seq[Try[T]]): Either[Seq[T], Seq[Throwable]] = {
      val (ss: Seq[Success[T]]@unchecked, fs: Seq[Failure[T]]@unchecked) =
        xs.partition(_.isSuccess)
    
      if (fs.isEmpty) Left(ss map (_.get))
      else Right(fs map (_.exception))
    }
    
    val zs = List(1,4,2,3,4,5,6)
    
    println(flatten2(map(xs))) // Right(List(java.lang.Exception: failed))
    println(flatten2(map(ys))) // Left(List(1, 2, 3, 5, 6))
    println(flatten2(map(zs))) // Right(List(java.lang.Exception: failed, 
                               //            java.lang.Exception: failed))
    

提交回复
热议问题