Scala:*.map(*) 运行 在 Future 中,如何中止地图?

Scala: *.map(*) running in a Future, how to abort map?

@volatile var breakRequested: Boolean = false
// ...
def futureFunc(): Option[Iterable[String]] = {
  val result = hugeList.map { item =>
    if(breakRequested) {
      // put exit code here
      // return None
      // throw AnException
      // what else?
    }
    item.toText() // time-expensive function
  }
  Some(result)
}
Future { futureFunc() }

鉴于有人将 breakRequested 标志设置为 true:我该如何退出 map

我尝试了什么:

return None => 这样一个return变成了一个scala.runtime.NonLocalReturnControl: 我试图捕获这个错误,但它似乎无法捕获(绕过try/catch).

object Cancelled extends Exception: 我试着扔了这个但是也没能接住它。

当我通过 SBT 运行 应用程序时,所有异常都显示在命令行中。

如果可能的话,我更喜欢没有 try/catch 的解决方案。

对于快速解决方案,您可以将 hugeList 转换为 Iterator,然后使用 takeWhile:

...
val result = hugeList.toIterator
  .takeWhile(_ => !breakRequested)
  .map { item => 
    item.text
  }
...

编辑: Scala 的 Future 没有取消,但 twitter 的 Future 有。要取消这个使用方法raise.

也可以自己写map,例如:

@annotation.tailrec def map[T,R](
  src: List[T], 
  cancel: => Boolean, 
  dsc: List[R] = List.empty[R])(f: T => R):List[R] = src match {
    case _ if cancel => dsc
    case h :: t => map(t, cancel, f(h) :: dsc)(f)
    case Nil => dsc
}
Future{map(hugeList, breakRequested)(_.text)}

如果不需要这个结果,可以再创建一个future,这个future会在你的breakRequested改变后完成。并使用方法 Future.firstCompletedOf.