用理解来构建期货

Vid*_*dya 3 scala future for-comprehension reactivemongo

我有一个使用ReactiveMongo和MongoDB的Play Framework应用程序,我有以下代码:

def categories(id: String): Future[Vector[Category]] = {...}
....
val categoriesFuture = categories(id)
for {
  categories: Vector[Category] <- categoriesFuture
  categoryIdsWithoutPerson: Vector[BSONObjectID] <- findCategoryIdsWithoutPerson(categories.map(_.id), personId) //Returns Future[Vector[BSONObjectID]]
  categoriesWithoutPerson: Vector[Category] <- categories.filter(category => categoryIdsWithoutPerson.contains(category.id)) //Play cites the error here
} yield categoryIdsWithoutPerson
Run Code Online (Sandbox Code Playgroud)

为了解释这个代码,我去取VectorCategories包裹在Future,因为这是ReactiveMongo如何汇总.在for理解中,我使用它Vector来从数据库中获取id列表.最后,我使用一个filter调用来保留那些id可以在id列表中找到的类别.

这一切看起来都相当简单.问题是Play在for理解的最后一行给出了以下编译错误:

pattern type is incompatible with expected type;
 found   : Vector[com.myapp.Category]
 required: com.myapp.Category
Run Code Online (Sandbox Code Playgroud)

我不确定为什么所需类型是单个实例Category.

我可以使用一些洞察我做错了什么和/或是否有更简单或更惯用的方法来实现这一点.

Noa*_*oah 5

它看起来像你想撰写FuturesVector.因为scala中的理解必须具有相同的更高类型,在您的情况下Future.当你展开"理解"的"糖"时,它只是呼唤flatMap一切.

for {
  categories <- categoriesFuture
  // I'm not sure what the return type is here, but I'm guessing it's a future as well
  categoryIdsWithoutPerson <- findCategoryIdsWithoutPerson(categories.map(_.id), personId)
  // Here we use = to get around need to flatMap
  categoriesWithoutPerson = categories.filter(category => categoryIdsWithoutPerson.contains(category.id))
} yield categoryIdsWithoutPerson
Run Code Online (Sandbox Code Playgroud)

你的代码消失了:

categoriesFuture.flatMap(categories => 
  findCategoryIdsWithoutPerson(categories.map(_.id), personId).
    flatMap(categoryIdsWithoutPerson => 
       categories.filter(category => categoryIdsWithoutPerson.contains(category.id)).
          map(_ => categoryIdsWithoutPerson))
Run Code Online (Sandbox Code Playgroud)