Scala:要么,右,左
Scala: Either, Right, Left
我是 Scala 的新手,目前正在尝试使用 play 框架。
这是我写的工作代码:
def authenticate = Action (BodyParsers.parse.json) { req =>
req.body.validate[AuthenticationForm].map {form =>
UserRepository.findByCredentials(form).map { user =>
user.apiKeys.find(_.deviceId == form.deviceId).map { apiKey =>
Ok(Json.toJson(apiKey))
}.getOrElse({
// HOW DO I TRANSFORM THIS INTO MORE BEAUTIFUL CODE
val createdApiKey = ApiKeyRepository.create(new ApiKey(form.deviceId, form.deviceId))
val userToWithNewApiKey = user.copy(apiKeys = user.apiKeys.:+(createdApiKey))
UserRepository.update(userToWithNewApiKey)
Ok(Json.toJson(createdApiKey))
})
}.getOrElse {
Unauthorized
}
}.getOrElse {
BadRequest
}
}
嗯,这看起来不太好。我们能做得更好吗?我还不能。但是我看到了这个 Whosebug post: 看起来很不错 :)
现在我想知道如何转换我的代码,使其看起来像给定的示例。当然我已经试过了,但我无法编译,也不知道如何处理注释后的代码("HOW DO I TRANSFORM THIS INTO MORE BEAUTIFUL CODE")。
在我的例子中,我使用 play.api.mvc.Result 而不是上面 link 中给出的 "Failure"。那么我的 Either[play.api.mvc.Result, ?WhatHere?] 应该是什么类型的呢?
此致
编辑: 我接受了特拉维斯的回答。非常感谢。
对于任何感兴趣的人来说,我可以编写更好看的代码,感谢 Travis:
def getApiKey(user: User, deviceId: String) : ApiKey = {
user.apiKeys.find(_.deviceId == deviceId).getOrElse {
val createdApiKey =
ApiKeyRepository.create(new ApiKey(deviceId, deviceId))
val userToWithNewApiKey =
user.copy(apiKeys = user.apiKeys.:+(createdApiKey))
UserRepository.update(userToWithNewApiKey)
createdApiKey
}
}
def authenticate = Action (BodyParsers.parse.json) { req =>
(for {
form <- req.body.validate[AuthenticationForm].asOpt.toRight(BadRequest).right
user <- UserRepository.findByCredentials(form).toRight(Unauthorized).right
} yield {
Ok(Json.toJson(getApiKey(user, form.deviceId)))
}).merge
}
这是快速且未经测试的,但应该是一个不错的开始。首先,您可以通过使用 toRight
来折叠一些嵌套以获得 Either[Status, ?]
。 Either
不是一元的,但它的正确投影(我们可以使用 .right
得到)是。一旦不再可能失败,我们就使用 yield
来处理结果。我已经稍微重写了您的 apiKey
内容以避免重复 Ok(Json.toJson(key))
部分。
def authenticate = Action (BodyParsers.parse.json) { req =>
for {
form <- req.body.asOpt.toRight[Status](BadRequest).right
user <- UserRepository.findByCredentials(form).toRight[Status](
Unauthorized
).right
} yield {
val apiKey = user.apiKeys.find(_.deviceId == form.deviceId).getOrElse {
val createdApiKey =
ApiKeyRepository.create(new ApiKey(form.deviceId, form.deviceId))
val userToWithNewApiKey =
user.copy(apiKeys = user.apiKeys.:+(createdApiKey))
UserRepository.update(userToWithNewApiKey)
createdApiKey
}
Ok(Json.toJson(apiKey)): Status
}.e.merge
}
for
-理解的最终结果(即除 .e.merge
之外的所有内容)是 RightProjection[Status, Status]
。我们将其转换回带有 .e
的普通旧 Either[Status, Status]
。此时我们不再需要跟踪失败和成功之间的区别,所以我们将整个事情转换为 Status
和 .merge
.
我是 Scala 的新手,目前正在尝试使用 play 框架。
这是我写的工作代码:
def authenticate = Action (BodyParsers.parse.json) { req =>
req.body.validate[AuthenticationForm].map {form =>
UserRepository.findByCredentials(form).map { user =>
user.apiKeys.find(_.deviceId == form.deviceId).map { apiKey =>
Ok(Json.toJson(apiKey))
}.getOrElse({
// HOW DO I TRANSFORM THIS INTO MORE BEAUTIFUL CODE
val createdApiKey = ApiKeyRepository.create(new ApiKey(form.deviceId, form.deviceId))
val userToWithNewApiKey = user.copy(apiKeys = user.apiKeys.:+(createdApiKey))
UserRepository.update(userToWithNewApiKey)
Ok(Json.toJson(createdApiKey))
})
}.getOrElse {
Unauthorized
}
}.getOrElse {
BadRequest
}
}
嗯,这看起来不太好。我们能做得更好吗?我还不能。但是我看到了这个 Whosebug post: 看起来很不错 :)
现在我想知道如何转换我的代码,使其看起来像给定的示例。当然我已经试过了,但我无法编译,也不知道如何处理注释后的代码("HOW DO I TRANSFORM THIS INTO MORE BEAUTIFUL CODE")。 在我的例子中,我使用 play.api.mvc.Result 而不是上面 link 中给出的 "Failure"。那么我的 Either[play.api.mvc.Result, ?WhatHere?] 应该是什么类型的呢?
此致
编辑: 我接受了特拉维斯的回答。非常感谢。
对于任何感兴趣的人来说,我可以编写更好看的代码,感谢 Travis:
def getApiKey(user: User, deviceId: String) : ApiKey = {
user.apiKeys.find(_.deviceId == deviceId).getOrElse {
val createdApiKey =
ApiKeyRepository.create(new ApiKey(deviceId, deviceId))
val userToWithNewApiKey =
user.copy(apiKeys = user.apiKeys.:+(createdApiKey))
UserRepository.update(userToWithNewApiKey)
createdApiKey
}
}
def authenticate = Action (BodyParsers.parse.json) { req =>
(for {
form <- req.body.validate[AuthenticationForm].asOpt.toRight(BadRequest).right
user <- UserRepository.findByCredentials(form).toRight(Unauthorized).right
} yield {
Ok(Json.toJson(getApiKey(user, form.deviceId)))
}).merge
}
这是快速且未经测试的,但应该是一个不错的开始。首先,您可以通过使用 toRight
来折叠一些嵌套以获得 Either[Status, ?]
。 Either
不是一元的,但它的正确投影(我们可以使用 .right
得到)是。一旦不再可能失败,我们就使用 yield
来处理结果。我已经稍微重写了您的 apiKey
内容以避免重复 Ok(Json.toJson(key))
部分。
def authenticate = Action (BodyParsers.parse.json) { req =>
for {
form <- req.body.asOpt.toRight[Status](BadRequest).right
user <- UserRepository.findByCredentials(form).toRight[Status](
Unauthorized
).right
} yield {
val apiKey = user.apiKeys.find(_.deviceId == form.deviceId).getOrElse {
val createdApiKey =
ApiKeyRepository.create(new ApiKey(form.deviceId, form.deviceId))
val userToWithNewApiKey =
user.copy(apiKeys = user.apiKeys.:+(createdApiKey))
UserRepository.update(userToWithNewApiKey)
createdApiKey
}
Ok(Json.toJson(apiKey)): Status
}.e.merge
}
for
-理解的最终结果(即除 .e.merge
之外的所有内容)是 RightProjection[Status, Status]
。我们将其转换回带有 .e
的普通旧 Either[Status, Status]
。此时我们不再需要跟踪失败和成功之间的区别,所以我们将整个事情转换为 Status
和 .merge
.