【问题标题】:For Comprehension Return type对于理解返回类型
【发布时间】:2018-08-05 06:18:19
【问题描述】:

我试图从理解中返回 Future[Vector[String]],但我将 Future[Nothing] 作为我的返回类型。如何将 Future[Nothing] 返回类型转换为 Future[Vector[String]]? 这是代码sn-p:

def findProjectId(projectName: String, userId: String): Future[Nothing] = {
    for {
      projectIds <- dBService.fetchProjectIdByProjectName(projectName) // projectIds is Vector[String]
      pid <- projectIds
      projectId <- dBService.filterProjectId(pid, userId) // ProjectId is Vector[String]
      if projectId.nonEmpty
    } yield {
      projectId map {
        projectid =>
          dBService.fetchRoleId map { // fetchRoleId returns Future[Vector[String]]
            case Vector(rid) => dBService.fetchCollaborator(projectid, rid) map { // fetchCollaborator returns Future[Vector[String]]
              listOfcollabs =>
                if (listOfcollabs.nonEmpty) {
                  listOfcollabs ++ Vector(userId)
                }
                else {
                  Vector(userId)
                }
            }
          }
      }
    }
  }

dbService 方法的签名是:

  def checkCollaboratorOrAdmin(userId: String, projectId: String, roleId: String): Future[Vector[String]] = {
    dbComponent.db.run(checkAdminOrCollab(roleId))
  }

  def fetchRoleId: Future[Vector[String]] = {
    dbComponent.db.run(fetchRole)
  }

  def fetchCollaborator(roleId: String, projectId: String): Future[Vector[String]] = {
    dbComponent.db.run(fetchCollaborators(roleId, projectId))
  }

  def fetchProjectIdByProjectName(projectName: String) = {
    dbComponent.db.run(fetchProjectId(projectName))
  }

  def filterProjectId(projectId: String, userId: String) = {
    dbComponent.db.run(filterProjectIdByUserId(projectId, userId))
  }

这些方法依次调用:

  def fetchRoleId(userId: String, projectId: String): SqlStreamingAction[Vector[String], String, Effect] = {
    sql"""select distinct(role_id) from project_user_role where user_id=$userId and project_id=$projectId""".as[String]
  }

  def checkAdminOrCollab(roleId: String): SqlStreamingAction[Vector[String], String, Effect] = {
    sql"""select role_id from roles where role_id=$roleId and role_name="collaborator" """.as[String]
  }

  def fetchRole(): SqlStreamingAction[Vector[String], String, Effect] = {
    sql"""select role_id from roles where role_name="collaborator"""".as[String]
  }

  def fetchCollaborators(roleId: String, projectId: String): SqlStreamingAction[Vector[String], String, Effect] = {
    sql"""select user_id from project_user_role where roleId=$roleId and project_id=$projectId""".as[String]
  }

  def fetchProjectId(projectName: String): SqlStreamingAction[Vector[String], String, Effect] = {
    sql"""select project_id from projects where project_name=$projectName""".as[String]
  }

  def filterProjectIdByUserId(projectId: String, userId: String): SqlStreamingAction[Vector[String], String, Effect] = {
    sql"""select project_id from project_user_role where project_id=$projectId and user_id=$userId""".as[String]
  }

【问题讨论】:

  • 您可以发布 dBService 方法的签名吗?具体是每个的完整返回类型?
  • 并且为了更好的可读性,还把你所有的提取放在里面以便理解。
  • @AssafMendelson 我已经添加了数据库服务方法的签名
  • @jyoti 你能在 fetchProjectIdByProjectName 和 filterProjectId 的签名中添加返回类型吗?

标签: scala list for-loop scala-collections for-comprehension


【解决方案1】:

我猜Future[Nothing] 来自 IntelliJ 提示,而不是编译器本身。编译器给出了几个错误,第一个来自这一行:

pid <- projectIds

这是我得到的错误:

Test.scala:47:13: 类型不匹配;

发现[错误]:scala.collection.immutable.Vector[Int]

需要[错误]:scala.concurrent.Future[?]

问题在于for 表达式试图使用mapflatMapfilter 调用来构建Future[_] 类型的值。 (for 的集合类型是for 中第一个表达式的集合类型)。 flatMap on Future 接受 Future 并将 Future[Future[_]] 转换为 Future[_]。但是你给它一个不支持的Vector

我也不确定更广泛的逻辑,因为您有两个嵌套的 Vectors(projectIds 和 listOfCollabs),但没有将其展平为单个向量的机制。

您可能想看看使用Future.traverseFuture.sequenceFuture 列表转换为Future[List]

将其分解为一些命名函数也很有意义,以使代码更易于理解并提供更好的隔离问题的机会。

更新

此代码将调用适当的函数并返回结果。返回类型是Future[Vector[Vector[Vector[String]]]],因为每个dBService 调用都会返回Future[Vector[String]],所以你会嵌套Vectors。从问题中不清楚如何将其展平为您想要的结果,但它应该很简单。 (最后一次调用的结果被 case 语句展平,这就是为什么有 4 个 dBService 调用但只有 3 个嵌套的 Vectors

def findProjectId(projectName: String, userId: String): Future[Vector[Vector[Vector[String]]]] = {
  dBService.fetchProjectIdByProjectName(projectName).flatMap { projectIds =>
    Future.traverse(projectIds) { pid =>
      dBService.filterProjectId(pid, userId).flatMap { projectId =>
        Future.traverse(projectId) { projectid =>
          dBService.fetchRoleId.flatMap { // fetchRoleId returns Future[Vector[String]]
            case Vector(rid) =>
              dBService.fetchCollaborator(projectid, rid) map { // fetchCollaborator returns Future[Vector[String]]
                _ ++ Vector(userId)
              }
          }
        }
      }
    }
  }
}

您可以只取其中一些Vectors 的第一个元素,这样可以简化代码。

Future.traverse(collection)(f) 等价于Future.sequence(collection.map(f)),但布局更好,效率可能更高。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-23
    • 1970-01-01
    • 2013-10-30
    • 2023-01-11
    相关资源
    最近更新 更多