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

Sim*_*n C 8 scala for-comprehension

假设我有:

val res:Future[Option[Boolean]] = Future(Some(true))
Run Code Online (Sandbox Code Playgroud)

我能做到:

res.map(opt => opt.map(r => print(!r)))
Run Code Online (Sandbox Code Playgroud)

我想对此的理解是:

for {
   opt <- res
   r <- opt
} yield (print(!r))
Run Code Online (Sandbox Code Playgroud)

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

error: type mismatch;
found   : Option[Unit]
required: scala.concurrent.Future[?]
r <- opt
Run Code Online (Sandbox Code Playgroud)

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

注意:这是我目前使用许多Future [Option [Boolean]]变量的问题的简化,我想在for comprehension中一起使用它们.

Rex*_*err 12

理解力真的让它看起来应该都能起作用,不是吗?但是让我们考虑一下你的要求.

首先,请注意forun-nests:

for {xs <- List(List(5)); x <- xs} yield x
Run Code Online (Sandbox Code Playgroud)

产生

List(5)
Run Code Online (Sandbox Code Playgroud)

现在,我们甚至没有进入类型签名或desugaring,我们可以考虑List用一些任意类型替换T,我们将调用包含的类型A:

for { xs <- T(T(a: A)); x <- xs } yield x
Run Code Online (Sandbox Code Playgroud)

我们应该得到一个

T[A]
Run Code Online (Sandbox Code Playgroud)

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

好的,但是呢

for { xs <- T(U(a: A)); x <- xs } yield x
Run Code Online (Sandbox Code Playgroud)

?这比两件事具有相同嵌套的情况更为笼统.好吧,如果TU两者都有一个共同的超类型S,那么我们就可以查看整个事情S(S(a: A)),所以我们至少得到一个S回来.但是在一般情况下呢?

底线是它取决于.例如,让我们考虑一下T=Future,U=Option.我们有以下可能性:

Success(Some(a))
Success(None)
Failure(t: Throwable)
Run Code Online (Sandbox Code Playgroud)

现在,我们能否提出任何连贯的解缠政策?如果我们打开一个Future,那么A你对这个Success(None)案子有什么用?您没有可用的返回.同样地,如果你试图征服外部Future,你怎么知道,如果没有明确地以某种方式向编译器陈述它Failure应该被映射到None(如果确实它应该 - 也许它应该是默认的!).

所以最重要的是,你不能正确地做到这一点,而不指定每对应该发生什么T[U[_]].(我鼓励感兴趣的读者仔细阅读monadmonad变换器的教程.)

但是有一条出路:如果你可以明确地将你U变成一个T,或者你的T变成你的U,你可以利用展开功能.将a Option变为a 非常容易Future,因此最简单的解决方案是

for { opt <- res; r <- Future(opt.get) } yield r
Run Code Online (Sandbox Code Playgroud)

(只是让异常被抛出none.get).或者,你可以把它Future变成一个Option略带丑陋的东西

for { opt <- res.value.flatMap(_.toOption); r <- opt } yield r
Run Code Online (Sandbox Code Playgroud)


sen*_*nia 8

等效代码

for {
   opt <- res
   r <- opt
} yield (print(!r))
Run Code Online (Sandbox Code Playgroud)

不是

res.map(opt => opt.map(r => print(!r)))
Run Code Online (Sandbox Code Playgroud)

res.flatMap(opt => opt.map(r => print(!r)))
Run Code Online (Sandbox Code Playgroud)

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

对于maps 链,你可以使用嵌套for-comprehensions

for { opt <- res }
  for { r <- opt }
    print(!r)
Run Code Online (Sandbox Code Playgroud)

map看起来更好.

  • `foreach`是用于副作用的规范方法.`map`让你看起来像是期待某种信息丰富的回报价值.我承认OP要求提供地图,但值得指出.但是,对嵌套fors的好评! (3认同)

Jat*_*tin 5

好吧,for理解是在欺骗他们的样子.你的理解扩展到:

res.flatMap(opt => opt.map(r => print(!r))
Run Code Online (Sandbox Code Playgroud)

这显然是错误的,因为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
Run Code Online (Sandbox Code Playgroud)

以上产生:

res.flatMap[Option[Unit]](((opt: Option[Boolean]) => 
            toFuture[Option[Unit]](opt.map[Unit](((r: Boolean) => print(!r))))))
Run Code Online (Sandbox Code Playgroud)

编辑:如果您正在使用,您需要承担所有的痛苦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)))
Run Code Online (Sandbox Code Playgroud)

这样就不需要隐式了.编译器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))))))))
  }
Run Code Online (Sandbox Code Playgroud)