我的代码包含从调用Akka actor返回的一些scala.concurrent.Futures
因此,演员中的示例代码如下所示:
val ivResult: Future[Any] = ask(ivActor, ivId)
// perform mapping is a function of type (Any) => Unit
val ivMapping: Future[Unit] = ivResult.map(performingMapping)
// erLookup is a function of type (Any) => Future[Any]
val erResult: Future[Any] = ivResult.flatMap(erLookup)
等等。代码基本上由future.flatmap()。map()组成,用于执行聚合逻辑
我的问题是我想实现空安全逻辑,这样如果未来的结果为null,那么我们就不会抛出NullPointerExceptions
显然,我可以在每个函数中嵌入空值安全检查,但考虑到Scala的强大功能,这些看起来有点冗长。
因此,我想找出是否有更优雅的方法来做到这一点,也许是使用暗示等。
答案 0 :(得分:1)
Future
的结果已经表明它是否成功完成。
通常,在NPE上,您的代码会爆炸,未来会失败。
你说,请不要让我的代码爆炸,可能产生有害的副作用。
所以你想要一个有特殊失败状态的后卫。
类似的东西:
scala> object DeadFuture extends Exception with NoStackTrace
defined object DeadFuture
scala> implicit class SafeFuture[A](val f: Future[A]) {
| def safeMap[B](m: A => B)(implicit x: ExecutionContext) =
| f.map { a: A => if (a == null) throw DeadFuture else m(a) }(x)
| def safeFlatMap[B](m: A => Future[B])(implicit x: ExecutionContext) =
| f.flatMap { a: A => if (a == null) (Future failed DeadFuture) else m(a) }(x)
| }
然后
scala> case class Datum(i: Int)
defined class Datum
scala> def f(d: Datum): Int = 2 * d.i
f: (d: Datum)Int
scala> def g(d: Datum): Future[Int] = Future(2 * d.i)
g: (d: Datum)scala.concurrent.Future[Int]
scala> Future[Datum](null) safeMap f
res1: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@5fa5debb
scala> .value
res3: Option[scala.util.Try[Int]] = Some(Failure(DeadFuture$))
scala> def g(d: Datum): Future[Int] = Future(2 * d.i)
g: (d: Datum)scala.concurrent.Future[Int]
scala> Future[Datum](null) safeFlatMap g
res4: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@7f188fd
scala> .value
res5: Option[scala.util.Try[Int]] = Some(Failure(DeadFuture$))
可能有更好的方法来促成转换,所以你要保持理解。
for (i <- safely(futureInt)) f(i)