ope*_*sas 23 error-handling functional-programming scala exception
我已经看过很多次使用Option(对于简单值)或者[List [Error],T]来处理错误的scala代码.
这给了这样的代码
def createApplicationToken(accessToken: AccessToken): Either[List[Error], ApplicationToken] = {
// go to social info provider and fetch information
retrieveProviderInfo(accessToken).fold(
errors => Left(errors),
info => {
// try to find user using the info from the provider
// if it's not there, create user
User.findOrCreateFromProviderInfo(info).fold(
errors => Left(errors),
user => {
// try to create a fresh token and save it to the user
user.refreshApplicationToken.fold(
errors => Left(errors),
user => Right(user.token)
)
}
)
}
)
Run Code Online (Sandbox Code Playgroud)
这会产生一个不太好的代码嵌套,迫使你处理每一步的失败,并迫使你让所有的函数返回一个Either [...]
所以我想知道是否
在scala(或一般的函数式编程)中不鼓励使用异常
使用它们有任何缺点(关于不变性或代码并发性)
异常与某些原则或函数式编程相冲突
你可以想出一个更好的方法来编写给定的例子
-
一旦使用return语句找到错误,就可以通过退出函数来避免嵌套,但是在scala中也不鼓励使用return ...
Tra*_*own 24
以下版本使用的正确投影Either是monad,并且与您的代码完全等效:
def createApplicationToken(accessToken: AccessToken) = for {
info <- retrieveProviderInfo(accessToken).right
user <- User.findOrCreateFromProviderInfo(info).right
refr <- user.refreshApplicationToken.right
} yield refr.token
Run Code Online (Sandbox Code Playgroud)
并且在展示优势方面做得更好Either.
更一般地说,规则与Java中的规则相同:在特殊情况下使用异常.你也许会发现,你改变你的定义特殊的一点,当你在这个风格,如正在开发的,无效的用户输入是不是真的例外,超时的网络请求是不是真的例外,等等.
Either自Scala 2.12以来右偏您现在可以省略.right,因此以下代码与Scala 2.12相同:
def createApplicationToken(accessToken: AccessToken) = for {
info <- retrieveProviderInfo(accessToken)
user <- User.findOrCreateFromProviderInfo(info)
refr <- user.refreshApplicationToken
} yield refr.token
Run Code Online (Sandbox Code Playgroud)
正如 om-nom-nom 所说,我问了一个类似的问题: 在 Scala 中抛出异常,什么是“官方规则”
但这并不是我问过的唯一一个可能让您感兴趣的问题,因为我曾经使用大量样板代码和大量缩进级别进行编码,因为模式匹配等...
您可以查看这些链接: Handling failures with Each -> Where is the stacktrace?
有点与错误处理相关,您可能会感兴趣: Scala 中的方法参数验证,用于理解和单子 在其中 Travis Brown 给出了更详细的答案,关于使用应用函子和 Scalaz 进行快速失败(第一个错误阻止了process) 或收集一组操作的所有错误同样的问题:当返回类型为 Option[Error] 时处理快速失败失败
您也可以检查使用按名称参数执行操作序列的链接。这可能是在理解中使用正确投影的一个很好的替代方案,但您无法创建中间结果:( 在 Scala 中使用一系列按名称参数进行验证? 我不知道它是否可以与您的代码一起使用例如,但在这种情况下我不这么认为(假设您的 refreshApplicationToken 没有副作用并返回一个新创建的不可变用户实例,而不是改变令牌变量)
| 归档时间: |
|
| 查看次数: |
4094 次 |
| 最近记录: |