未来[选项[布尔]]用于理解..简单吧?

时间:2014-01-03 01:32:57

标签: scala for-comprehension

假设我有:

val res:Future[Option[Boolean]] = Future(Some(true))

我能做到:

res.map(opt => opt.map(r => print(!r)))

我想对此的理解是:

for {
   opt <- res
   r <- opt
} yield (print(!r))

但这不起作用! 我收到错误,即:

error: type mismatch;
found   : Option[Unit]
required: scala.concurrent.Future[?]
r <- opt

如何在for comprehension中使用Future [Option [Boolean]]来提取或转换布尔值?

注意:这是我目前使用许多Future [Option [Boolean]]变量的问题的简化,我想在一起使用一起理解。

3 个答案:

答案 0 :(得分:12)

for-comprehension真的让它看起来应该都可行,不是吗?但是让我们考虑一下你的要求。

首先,请注意for取消嵌套:

for {xs <- List(List(5)); x <- xs} yield x

产生

List(5)

现在,我们甚至没有进入类型签名或贬低,我们可以考虑将List替换为任意类型T,我们将调用包含的类型A:< / p>

for { xs <- T(T(a: A)); x <- xs } yield x

我们应该得到一个

T[A]

回来(可能是我们投入的那个,但是这些类型实际上并没有向我们承诺)。

好的,但是呢?

for { xs <- T(U(a: A)); x <- xs } yield x

?这比两件事具有相同嵌套的情况更为笼统。好吧,如果TU都有一个共同的超类型S,那么我们只能将整个内容视为S(S(a: A)),因此我们至少会获得S T=Future 1}}回来。但是在一般情况下呢?

底线是它取决于。例如,让我们考虑U=OptionSuccess(Some(a)) Success(None) Failure(t: Throwable) 的情况。我们有以下可能性:

Future

现在,我们能否提出任何一致的解缠政策?如果我们打开A,那么Success(None)用于Future的情况是什么?您没有可用的返回。同样,如果你试图征服外部Failure,你怎么知道,如果没有明确地向编译器陈述它,None应该映射到T[U[_]](如果它确实应该 - - 它应该是默认的!)。

所以最重要的是,你只是不能正确地执行此操作而不指定每对U应该发生什么。 (我鼓励感兴趣的读者仔细阅读monadsmonad transformers上的教程。)

但还有一条出路:如果您可以明确地将T变为T,或将U明确变为Option,则可以利用展开能力。将Future转换为for { opt <- res; r <- Future(opt.get) } yield r 非常容易,因此最简单的解决方案是

none.get

(只允许在Future上抛出异常)。或者,您可以将Option转换为for { opt <- res.value.flatMap(_.toOption); r <- opt } yield r 稍微丑陋的

{{1}}

答案 1 :(得分:8)

的等效代码
for {
   opt <- res
   r <- opt
} yield (print(!r))

不是

res.map(opt => opt.map(r => print(!r)))

res.flatMap(opt => opt.map(r => print(!r)))

在这种情况下没有任何意义。

对于map的链,您可以使用嵌套的for-comprehensions

for { opt <- res }
  for { r <- opt }
    print(!r)

map看起来更好。

答案 2 :(得分:5)

嗯,for理解是在欺骗他们的样子。你的理解扩展到:

res.flatMap(opt => opt.map(r => print(!r))

这显然是错误的,因为flatMap期望返回类型为Future[T],而您提供Option[Unit]

虽然有时候,对于代码整洁,你会希望有一个带有许多这种表达式的for循环。在这些情况下,您可以:

 scala> implicit def toFuture[T](t: => T):Future[T] = {
     | val p = Promise[T]()
     | p.tryComplete(Try(t))
     | p.future
     | }

scala>  for {
     |          opt <- res
     |          r <- opt
     |       }  yield {print(!r)}

false

以上产生:

res.flatMap[Option[Unit]](((opt: Option[Boolean]) => 
            toFuture[Option[Unit]](opt.map[Unit](((r: Boolean) => print(!r))))))

编辑:如果你使用yield,你需要承担所有的痛苦。如果您不希望将for理解用作表达式,那么您可以按照自己的意愿进行操作:

scala> val i = Future(Some(true))
i: scala.concurrent.Future[Some[Boolean]] = scala.concurrent.impl.Promise$DefaultPromise@6b24a494

scala>   val j = Option(1)
j: Option[Int] = Some(1)

scala>   val k = Right(1).right
k: scala.util.Either.RightProjection[Nothing,Int] = RightProjection(Right(1))

scala>   
     |   for{
     |     x <- i
     |     y <- j
     |     z <- k
     |   }{
     |     println(i,j,k)
     |   }

(scala.concurrent.impl.Promise$DefaultPromise@6b24a494,Some(1),RightProjection(Right(1)))

这种方式不需要隐式。编译器在每个连接处使用foreach-Xprint:typer给出:

i.foreach[Unit](((x: Option[Boolean]) => 
     j.foreach[Any](((y: Int) => 
         k.foreach[Unit](((z: Int) =>    println(scala.this.Tuple3.apply[scala.concurrent.Future[Option[Boolean]], Option[Int], Either.RightProjection[Nothing,Int]](i, j, k))))))))
  }