我们的代码库中有一个函数,其签名如下:
def hasPermission(...): Try[Unit]
它基本上检查用户是否有权对某个项目执行某项操作。如果用户具有权限,则返回空Success
,如果没有,则返回具有特定异常类型的Failure
。这个功能经常在这样的理解中使用:
for {
_ <- hasPermission(...)
res <- doSomething()
} yield res
这似乎是不好的做法,但我不能清楚地阐明为什么我有这种感觉。对我而言,似乎hasPermission
应该只返回Boolean
。
这适用于Try
吗?
编辑:我认为我的问题与链接的问题不同,因为它更具体。那个问题是关于返回Try [Unit]的一般性问题,我认为在某些情况下这是可以接受的。
答案 0 :(得分:2)
如果方法显示hasPermission
,那么我会说它应该返回Boolean
或Try[Boolean]
。 Try[Unit]
不像Try[Boolean]
那么明显,调用者必须检查异常以判断它是否没有权限,或者是否无法检索权限信息。
现在说,通常调用hasPermission
然后根据结果行事可能会导致竞争条件(例如,如果在调用hasPermission
后撤消权限)。因此,通常最好是def doSomething(...): Try[Unit]
,然后举起例如NoPermissionException
。
答案 1 :(得分:0)
Generally, the use of exceptions for control flow is an anti-pattern
Try
尝试(没有双关语)封装该流量控件,但如果您实际上需要使用异常,则没有理由这样做。 Scala 2.12的Either
实现似乎接近您可能想要的内容:
要么是偏右的,这意味着
Right
被认为是操作的默认情况。如果是Left
,则map
和flatMap
等操作会使Left
值保持不变:
假设您正在实施Web服务器,并且此逻辑控制着特定路径:
type Request = ...
type Response = String
type ResponseOr[+T] = Either[Response, T]
def checkPermission: ResponseOr[Unit] =
if(hasPermission) Right(())
else Left("insufficient permissions")
def doSomething(req: Request): ResponseOr[Something] =
if(argumentsAreBad(req)) Left("arguments are bad!")
else Right(new Something)
def makeResponse(result: Something): Response = ???
def handleIt(req: Request): Response = {
val result = for {
_ <- checkPermission
result <- doSomething
} yield makeResponse(result)
result.merge // special method for `Either[T, T]` that gives a `T`
}
您会看到与Success
vs Failure
类似的行为 - 将Left
视为与Failure
类似,如果在任何时候,其中一个是flatMap / map步骤返回Left
,这是最终结果,其余的是&#34;跳过&#34;。无需例外。