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

 昀尧约_146 发布于 2023-02-06 19:59

假设我有:

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]]变量的问题的简化,我想在for comprehension中一起使用它们.

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

    首先,请注意forun-nests:

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

    产生

    List(5)
    

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

    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,U=Option.我们有以下可能性:

    Success(Some(a))
    Success(None)
    Failure(t: Throwable)
    

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

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

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

    for { opt <- res; r <- Future(opt.get) } yield r
    

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

    for { opt <- res.value.flatMap(_.toOption); r <- opt } yield r
    

    2023-02-06 20:02 回答
  • 好吧,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))))))))
      }
    

    2023-02-06 20:03 回答
  • 等效代码

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

    不是

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

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

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

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

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

    map看起来更好.

    2023-02-06 20:04 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有