【问题标题】:Scala adding elements to seq and handling futures, maps, and async behaviorScala 向 seq 添加元素并处理期货、映射和异步行为
【发布时间】:2018-01-19 14:48:43
【问题描述】:

我还是 scala 的新手,还不太了解 Futures/Maps/Flatmaps/Seq 的概念以及如何正确使用它们。

这就是我想做的(伪代码):

 def getContentComponents: Action[AnyContent] = Action.async {
        contentComponentDTO.list().map( //Future[Seq[ContentComponentModel]] Get all contentComponents
          contentComponents => contentComponents.map( //Iterate over [Seq[ContentComponentModel]
            contentComponent => contentComponent.typeOf match { //Match the type of the contentComponent
              case 1 => contentComponent.pictures :+ contentComponentDTO.getContentComponentPicture(contentComponent.id.get) //Future[Option[ContentComponentPictureModel]] add to _.pictures seq
              case 2 => contentComponent.videos :+ contentComponentDTO.getContentComponentVideo(contentComponent.id.get) //Future[Option[ContentComponentVideoModel]] add to _.videos seq
            }
          )
            Ok(Json.toJson(contentComponents)) //Return all the contentComponents in the end
        )
    }

我想像这样将Future[Option[Foo]] 添加到contentComponent.pictures: Option[Seq[Foo]]:

case 2 => contentComponent.pictures :+ contentComponentDTO.getContentComponentPicture(contentComponent.id.get) //contentComponent.pictures is Option[Seq[Foo]]

最后通过json将整个contentComponent返回给前端。

我知道这可能与最终的实际代码相去甚远,但我希望你明白这一点。谢谢!

【问题讨论】:

  • 问题太宽泛/不清楚
  • 请您也尽自己的一份力,想出一个更简单的例子。这是一个非常简单的问题,但您的示例增加了许多不相关的复杂性。
  • 哦,好吧,我想你可能需要上下文。将编辑
  • @cchantep 这有帮助吗?你对我有什么期望?我真的不能把它归结为更多。

标签: scala playframework playframework-2.0


【解决方案1】:

我将忽略您的代码,专注于简短且有意义的内容:

我想将 Future[Option[Foo]] 添加到 contentComponent.pictures: Option[Seq[Foo]] 像这样:

让我们这样做,关注代码的可读性:

// what you already have
val someFuture: Future[Option[Foo]] = ???
val pics: Option[Seq[Foo]] = contentComponent.pictures
// what I'm adding
val result: Future[Option[Seq[Foo]]] = someFuture.map {
  case None => pics
  case Some(newElement) => 
    pics match {
      case None => Some(Seq(newElement)) // not sure what you want here if pics is empty...
      case Some(picsSequence) => Some(picsSequence :+ newElement)
    }
}

为了展示flatMap 的示例,假设您在另一个未来需要result 未来的结果,只需这样做:

val otherFuture: Future[Any] = ???
val everything: Future[Option[Seq[Foo]]] = otherFuture.flatmap { otherResult =>
  // do something with otherResult i.e., the code above could be pasted in here...
  result
}

【讨论】:

    【解决方案2】:

    我的回答将尝试帮助您解决一些概念性子问题,这些子问题构成您的整个较大问题的一部分。

    flatMap 和 for-yield

    flatMap 的一个要点是帮助解决Pyramid of Doom 的问题。这发生在你有 嵌套在结构中的结构 嵌套在结构中的结构 ...

    doA().map { resultOfA =>
      doB(resultOfA).map { resolutOfB =>
        doC(resultOfB).map { resultOfC =>
          ...
        }
      }
    }
    

    如果你使用for-yield,你会得到开箱即用的flatMap,它允许你

    把金字塔弄平

    让你的代码看起来更像线性结构

    for {
    
      resultOfA <- doA
      resultOfB <- doB(resultOfA)
      resultOfC <- doC(resultOfB)
    ...
    } yield {...}
    

    软件工程中有一条经验法则是,深度嵌套的结构更难调试和推理,所以 我们努力尽量减少嵌套。尤其是在处理Futures 时,您会遇到这个问题。

    Future 上的映射与序列上的映射

    映射通常首先考虑的是对序列的迭代,这可能会导致理解 根据迭代一个序列,映射Future。我的建议是不要使用 iteration 概念 试图理解对Futures、Options 等的映射。在这些情况下,最好将映射视为破坏结构的过程 这样您就可以了解结构内部的元素。可以将映射可视化为

    打碎核桃的壳,这样你就可以得到里面美味的核仁,然后重建壳。

    Futures 和单子

    当你尝试更多地了解Futures 以及当你开始处理像Future[Option[SomeType]] 这样的类型时,你将不可避免地 偶然发现有关 monads 及其神秘术语的文档可能会吓跑你。如果发生这种情况,将单子(其中Future 是一个特定的实例)简单地考虑可能会有所帮助

    您可以将其粘贴到for-yield 中,以便您可以在 美味的核桃仁,同时避开末日金字塔。

    【讨论】:

      猜你喜欢
      • 2017-09-30
      • 2014-06-15
      • 1970-01-01
      • 1970-01-01
      • 2014-03-29
      • 2014-12-22
      • 1970-01-01
      • 1970-01-01
      • 2011-11-01
      相关资源
      最近更新 更多