首页 文章

“必需:scala.collection.GenTraversableOnce [?]”错误来自于此理解

提问于
浏览
0

我是一个新的scala开发人员,陷入类型问题 . 有时候,我仍然会通过处理期货而绊倒,我认为这是其中一次 . 这部分代码......

// do some stuff with a collection of List[Future[ClientArticle]]
Future.sequence(listFutureClonedArticles).map( clonedArticles =>
    for {
        // create persistent records of the cloned client articles, and discard the response
        _ <- clonedArticles.map(clonedArticle => clientArticleDAO.create(clonedArticle))

        // add cloned articles to a batch of articles, and discard the response
        _ <- batchDAO.addArticlesToExistingBatch(destinationBatch._id, clonedArticles.map(_._id))

    } yield {

        // ultimately just return the cloned articles
        clonedArticles
    }
)

...正在产生此编译器错误:

[error] /.../app/services/BatchServiceAPI.scala:442: type mismatch;
[error]  found   : scala.concurrent.Future[List[model.ClientArticle]]
[error]  required: scala.collection.GenTraversableOnce[?]
[error]                             _ <- batchDAO.addArticlesToExistingBatch(destinationBatch._id, clonedArticles.map(_._id))
[error]                               ^

addArticlesToExistingBatch()的参数似乎是方法签名的正确类型:

/** Adds a list of id's to a batch by it's database ID. */
def addArticlesToExistingBatch(batchId: ID, articleIds: List[ID])(implicit ec: ExecutionContext): Future[Return]

当然,我可能会误解理解是如何运作的 . 我不明白如何在< - 运算符处发生错误,也不知道在那时如何/为什么会出现类型期望 .

任何人都可以帮助我理解这里需要做什么吗?

=== 21 minutes later... ===

有趣 . 当我停止使用for comprehension并将它们分成两个单独的 Map 时,它会编译 .

// create cloned client articles
Future.sequence(listFutureClonedArticles).map(clonedArticles =>
    clonedArticles.map(clonedArticle => clientArticleDAO.create(clonedArticle)))

// add cloned articles to destination batch
Future.sequence(listFutureClonedArticles).map(clonedArticles =>
    batchDAO.addArticlesToExistingBatch(destinationBatch._id, clonedArticles.map(_._id)))

所以,是的,我想我仍然不太了解理解 . 我认为它们可以用于汇总几个Future操作 . 为什么在这种情况下不起作用

1 回答

  • 2

    理解是 flatMapmap 的组合 . 带有 <- 的每一行都被转换为 flatMap ,但最后一行被转换为 map .

    所以,你编码

    for {
        // create persistent records of the cloned client articles, and discard the response
        _ <- clonedArticles.map(clonedArticle => clientArticleDAO.create(clonedArticle))
        // add cloned articles to a batch of articles, and discard the response
        _ <- batchDAO.addArticlesToExistingBatch(destinationBatch._id, clonedArticles.map(_._id))
      } yield {
        // ultimately just return the cloned articles
        clonedArticles
      }
    

    转换为

    clonedArticles.map(clonedArticle => clientArticleDAO.create(clonedArticle)).flatMap { _ =>
        batchDAO.addArticlesToExistingBatch(destinationBatch._id, clonedArticles.map(_._id)).map { _ =>
          clonedArticles
        }
      }
    

    as clonedArticlesList ,列表的 flatMap 签名是

    final override def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That = ???
    

    如果你查看 flatMap 所需的参数,它需要一个函数 A => GenTraversableOnce ,但在你的函数中,你传递的函数是 A => Future ,这就是问题所在 .

    我试图用你可以尝试的简单函数来模仿你的问题:

    import scala.concurrent._
      import scala.concurrent.ExecutionContext.Implicits.global
      val listOfFuture: List[Future[Int]] = (1 to 10).map(Future(_)).toList
      def f(i: List[Int]): Future[String] = Future(s"very complex logic: ${i.sum}")
      def create(i: Int): Future[Unit] = Future(println(s"creating something complex: $i"))
    
     Future.traverse(listOfFuture){ futureX =>
       for {
         x <- futureX
         _ <- create(x)
       } yield x
      }.flatMap(f)
    

相关问题