scala - 用于从 for 理解中恢复的更好语法

标签 scala future for-comprehension

我有许多函数返回一个 future,它是 for 理解的结果,但我需要在退出时从一些可能的失败中恢复。标准语法似乎将 for 理解捕获为中间结果,如下所示:

def fooBar(): Future[String] = {
  val x = for {
    x <- foo()
    y <- bar(x)
  } yield y
  x.recover {
    case SomeException() => "bah"
  }
}

我发现的最好的替代方法是将整个内容括在括号中以便理解:

def fooBar(): Future[String] = (for {
  x <- foo()
  y <- bar(x)
} yield y).recover {
  case SomeException() => "bah"
}

这看起来更像是一种捷径,而不是语法的改进,所以我想知道是否有更好的方法将恢复编织到理解中?

最佳答案

一些大括号调整会有所帮助,尽管有些人更喜欢在多行表达式中使用大括号而不是括号:

scala> def f = (
     |   for {
     |     x <- foo;
     |     y <- bar(x)
     |   } yield y
     | ) recover {
     |   case _: NullPointerException => -1
     | }
f: scala.concurrent.Future[Int]

如果你不喜欢

scala> foo flatMap bar recover { case _: NullPointerException => -1 }
res9: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@3efe7086

你可以使用所有语法:

object Test extends App {
  import concurrent._
  import duration.Duration._
  import ExecutionContext.Implicits._
  type ~>[A, B] = PartialFunction[A, B]
  type NPE = NullPointerException
  class `recovering future`[A, R >: A](val f: Future[A], val pf: Throwable ~> R) {
    def map[B >: A <: R](m: A => B) = new `recovering future`[B, R](f map m, pf)
    def flatMap[B >: A <: R](m: A => Future[B]) = new `recovering future`[B, R](f flatMap m, pf)
    def recovered: Future[R] = f recover pf
  }
  object `recovering future` {
    implicit def `back to the future`[A, R >: A](x: `recovering future`[A, R]): Future[R] = x.recovered
  }
  implicit class `inline recoverer`[A](val f: Future[A]) {
    def recovering[B >: A](pf: Throwable ~> B) = new `recovering future`(f, pf)
  }

  def f = Future(8)
  def g(i: Int) = Future(42 + i)
  def e(i: Int): Future[Int] = Future((null: String).length)

朴素:

  for {
    x <- f
    y <- g(x)
  } Console println y   // 50

并且内联恢复:

  def compute: Future[Int] =
    for {
      x <- f recovering { case _: NPE => -1 }
      y <- g(x)
    } yield y
  Console println (Await result (compute, Inf))  // 50

或者显示失败的案例:

  def fail: Future[Int] =
    for {
      x <- f recovering { case _: NPE => -1 }
      y <- e(x)
    } yield y
  Console println (Await result (fail, Inf))  // -1
}

如果你那样挥杆。

关于scala - 用于从 for 理解中恢复的更好语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25732570/

相关文章:

scala - 导入 sbt 项目时出错,服务器访问错误, Unresolved 依赖项

Scala 编译器无法正确推断类型

c++ - 在设置值之前是否必须调用 promise.get_future() ?

arrays - 为了理解 Option 数组

Scala理解能力的表现

scala - Scala for/yield 的返回类型

java - 如何从 Play 框架标准输出中消除异常堆栈跟踪

java - 将 REPL 添加到 Java 项目的技巧

scala - 如何使用 Scala Future 的批处理函数?

scala - Future的onComplete和flatMap有什么区别?