错误处理
程序设计,尤其是软件工程中,处理错误是不可避免的,比较常见的方式有以下种:
if(f() == null)
手动判断方式try {} catch(Exception) {}
异常(Exception)方式Result<T>
方式
他们各有各自的优缺点
Kotlin Result<T>
Kotlin的Result<T>定义在Kotlin标准库中,无需额外导入库,其源码在这里可查看 stdlib/src/kotlin/util/Result.kt
创建Result
常用Result作为函数返回值
直接创建
例:
// 如果成功,则返回OK123456,否则返回错误(及其Exception)
fun f()
{
var f: Result<String> = Result.failure(Exception()) // 通过 failure 或 success 创建Result<T>
var s: Result<String> = Result.success("OK123456") // 通过 failure 或 success 创建Result<T>
return s
}
从Try-Catch方法转换
Result.runCatching函数可将Try-Catch方法转换为Result
val y: Result<Int> = Result.runCatching {
throw Exception()
1
}
// y == Result.failure(Exception())
解析Result
更多的时候是获得一个Result<T>,据其是success还是failure进行下一步操作,在这里有很多方法
getOr系列函数
包括
result.getOrNull() //返回一个可空类型,若失败则为空,否则为value,更适合喜欢 if(f() == null) 的人
result.getOrThrow() // 若失败,则抛出异常,更适合喜欢Exception方式的人
result.getOrDefault(defaultValue) // 若失败,则返回defaultValue参数
通过isSuccess判断 (不推荐)
展开
这种方式适合喜欢 if(f() == null) 的人,注意getOrNull返回的仍然是可空类型val result: Result
= f() if(result.isSuccess) { val x = result.getOrNull(); } else {
}
fold函数
fold函数可将错误处理的方式一并写入,适合较为简单的错误处理
val result: Result<String> = f()
val x: String = result.fold(
onSuccess = { "f() OK" },
onFailure = { "f() Failed" }
)
println(x)
处理Result
可使用map函数在不取出Result值的情况下对Result进行变换
var s = Result.success("OK123456")
s = s.map { it.substring(1..3) }
// s == Result.success("K12")
其他函数
其他诸如 recover,mapCatching,getOrElse
之类的函数,只是上面几种的变体
实现
sealed class Maybe<out T> {
object None :Maybe<Nothing>()
class Just<out T>(val x :T) :Maybe<T>()
}
fun <T,R> Maybe<T>.fmap(transform :(T) -> Maybe<R>) = when(this) {
Maybe.None -> Maybe.None
is Maybe.Just -> transform(this.x)
}
在C/C++中,可以使用std::variant
或union
: C++小技巧 实现Kotlin中的Result
小结
- 可使用
Result.success(value)
和Result.failure(Exception())
创建Result<T>
- 可使用
getOr
系列函数或fold
函数 解析Result<T>
- 可使用
map
函数处理Result<T>
,runCatching
函数从 Exception 方式转换为Result<T>