我正在尝试从中返回Future [Vector [String]]以进行理解,但是我将Future [Nothing]作为返回类型。如何将Future [Nothing]返回类型转换为Future [Vector [String]]? 这是代码段:
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]
}
答案 0 :(得分:4)
我猜测Future[Nothing]
来自IntelliJ提示,而不是编译器本身。编译器给出了两个错误,第一个错误来自此行:
pid <- projectIds
这是我得到的错误:
Test.scala:47:13:类型不匹配;
[错误]发现:scala.collection.immutable.Vector [Int]
[错误]必需:scala.concurrent.Future [?]
问题是for
表达式试图使用Future[_]
,map
和flatMap
调用来构建类型为filter
的值。 (for
的集合类型是for
中第一个表达式的集合类型)。 flatMap
上的Future
取Future
并将Future[Future[_]]
变成Future[_]
。但是,您给它提供了Vector
不受支持。
我也不确定更广泛的逻辑,因为您有两个嵌套的Vectors
(projectIds和listOfCollabs),但是没有将其扁平化为单个向量的机制。
您可能希望使用Future.traverse
或Future.sequence
将Future
的列表转换为Future[List]
。
将其分解为一些命名函数以使代码更易理解,并提供更好的隔离问题的机会。
此代码将调用适当的函数并返回结果。返回类型为Future[Vector[Vector[Vector[String]]]]
,因为每个dBService
调用都会返回Future[Vector[String]]
,因此您会嵌套Vector
。从这个问题尚不清楚如何将其展平为所需的结果,但是它应该很简单。 (最后一次调用的结果被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))
等效,但是布局更好,效率更高。