錯誤處理
程序設計,尤其是軟件工程中,處理錯誤是不可避免的,比較常見的方式有以下種:
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>
