【问题标题】:unable to compile a code with list of Future无法使用 Future 列表编译代码
【发布时间】:2016-12-30 22:05:50
【问题描述】:

StackOverflow 上有一些关于如何处理 Futures 列表的建议,但我想尝试自己的方法。但我无法编译以下代码

我有一份期货清单。 我想计算其中有多少通过或失败。我应该得到 (2,1) 我将它存储在一个元组中 我想采取的方法是遍历列表的每个元素。列表的元素是 Future[Int]。对于每个元素,我调用 flatMap 调用下一个递归循环(我假设如果调用 flatMap 则特定的未来会成功,所以我增加通过计数)。同样,我想在恢复和递增失败计数中调用下一个递归循环,但我得到了编译错误。

import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success, Try}
import scala.concurrent.duration._
import scala.language.postfixOps

object ConcurrencyExample extends App {

  type pass = Int
  type fail = Int

  val time = System.currentTimeMillis()

//use recursion to process each Future in the list 
  def segregate(l:List[Future[Int]]):Future[Tuple2[pass,fail]] = {
    def go(l:List[Future[Int]],t:Tuple2[pass,fail]):Future[Tuple2[pass,fail]] = {
        l match {
          case Nil => Future{t}
            //l is List of Future[Int]. flatMap each successful Future 
            //recover each failed Future
          case l::ls => {
            l flatMap (x => go(ls, (t._1 + 1, t._2)))
              **l.recover({ case e => go(ls, (t._1 + 1, t._2))})**//I get error here
          }
        }
    }
    go(l,(0,0))
  }

//hardcoded future
  val futures2: List[Future[Int]] = List(Future {
    1
  }, Future {
    2
  }, Future {
    throw new Exception("error")
  })


  val result = segregate(futures2)
  result onComplete {
    case Success(v) => println("pp:" + v)
    case Failure(v) => println("fp:" + v)
  }

  Await.result(result,1000 millis)
}

【问题讨论】:

    标签: scala


    【解决方案1】:

    @evan058 关于recover 的签名是正确的。但是您可以通过将 recover 更改为 recoverWith 来修复您的程序。

    recoverWithrecover 就像 flatMapmap

    这里是完整的解决方案(在文体上稍作改进):

    import scala.concurrent._
    import scala.concurrent.ExecutionContext.Implicits.global
    import scala.util.{Failure, Success, Try}
    import scala.concurrent.duration._
    import scala.language.postfixOps
    
    object ConcurrencyExample extends App {
    
      type pass = Int
      type fail = Int
    
      val time = System.currentTimeMillis()
    
      //use recursion to process each Future in the list
      def segregate[T](fs:List[Future[T]]):Future[(pass,fail)] = {
        def go(fs:List[Future[T]],r:Future[(pass,fail)]):Future[(pass,fail)] = fs match {
          case Nil => r
          case l::ls =>
            val fx = l.transform({_ => (1, 0)}, identity).recoverWith[(pass,fail)]({case _: Exception => Future(0, 1) })
            for (x <- fx; t <- r; g <- go(ls, Future(t._1+x._1,t._2+x._2))) yield g
        }
        go(fs,Future((0,0)))
      }
    
      //hardcoded future
      val futures2 = List(Future(1), Future(2), Future(throw new Exception("error")))    
    
      val result = segregate(futures2)
      result onComplete {
        case Success(v) => println(s"successes: ${v._1}, failures: ${v._2}")
        case Failure(v) => v.printStackTrace()
      }
    
      Await.result(result,1000 millis)
    }
    

    【讨论】:

    • 不会 OP 仍然有一个 (pass,fail) 而不是一些 U 其中U &gt;: Int
    • 啊,我明白你的意思了。看起来您需要asInstanceOf[Future[(pass,fail)]],否则它会抱怨获得Future[Any],但之后它会为我运行。
    • 男士 - 谢谢。你的意思是这个吗?代码编译但我得到一个运行时错误java.lang.ClassCastException: java.lang.Integer cannot be cast to scala.Tuple2我现在写的代码是flatMap (x =&gt; go(ls, (t._1 + 1, t._2))) l.asInstanceOf[Future[(pass,fail)]].recoverWith({ case e =&gt; go(ls, (t._1 + 1, t._2))})
    • 我重写了它——但我无法很好地在评论中格式化代码,所以我添加了一个新答案
    • 现在看起来好多了,虽然让它尾递归会很好。也许我稍后会回来工作。或者其他人会...
    【解决方案2】:

    如果你看docsrecover的签名是:

    def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U]
    

    您在l 上调用recover,这是一个Future[Int],所以recover 期待一个U &gt;: Int

    但是,您再次调用go,其返回类型为Future[(pass, fail)],而不是&gt;: Int

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-17
      • 2011-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多