作者:Erica Sadun,原文鏈接,原文日期:2015-08-27
譯者:CMB;校對:numbbbbb;定稿:千葉知風
假設你正在使用一個類型,當有錯誤時發生時你想要輸出異常發生時的上下文。通常你會使用一些內置的編譯器關鍵字:__FUNCTION__
, __LINE__
和 __FILE__
,這些關鍵詞提供了有關函數調用詳細的文本插值:
public struct Error: ErrorType {
let source: String; let reason: String
public init(_ reason: String, source: String = __FUNCTION__,
file: String = __FILE__, line: Int = __LINE__) {
self.reason = reason; self.source = "\(source):\(file):\(line)"
}
}
一行典型的 Error
輸出如下所示:
Error(source: "myFunction():<EXPR>:14", reason: "An important reason")
雖然這種結構能夠讓你捕獲出現異常的函數、文件和行號,但你無法捕捉沒有類型參數的原始父類型。為了捕獲該類型,需要在 Error
結構體構造器中包含“原始類型”,并向構造器中傳遞 self.dynamicType
參數。
public struct Error: ErrorType {
let source: String; let reason: String
public init(_ reason: String, type: Any = "",
source: String = __FUNCTION__,
file: String = __FILE__,
line: Int = __LINE__) {
self.reason = reason; self.source = "\(source):\(file):\(line):\(type)"
}
}
我很不喜歡這種額外添加類型參數的方式,它唯一的作用就是簡化錯誤生成。
public struct Parent {
func myFunction() throws {
throw Error("An important reason", type: self.dynamicType)}
}
do {try Parent().myFunction()} catch{print(error)}
// Error(source: "myFunction():<EXPR>:14:Parent", reason: "An important reason")
我更喜歡擴展 Contextualizable
來實現自動捕獲類型上下文。注意,默認實現的協議方法中用到了 self.dynamicType
,它不能被用在方法簽名中(譯者注:也就是說不能當做函數參數或者返回值)。
protocol Contextualizable {}
extension Contextualizable {
func currentContext(file : String = __FILE__, function : String = __FUNCTION__, line : Int = __LINE__) -> String {
return "\(file):\(function):\(line):\(self.dynamicType)"
}
}
結合上述兩種方法可以簡化整個過程輕松實現我們的目標。共享 Error
類型之后就可以把變量改成常量,并且把上下文相關代碼從 Error
構造器移動到遵循協議的類型中,這樣就可以自動繼承 currentContext
方法。
public struct Error: ErrorType {
let source: String; let reason: String
public init(_ source: String = __FILE__, _ reason: String) {
self.reason = reason; self.source = source
}
}
public struct Parent: Contextualizable {
func myFunction() throws {
throw Error(currentContext(), "An important reason")}
更新之后,錯誤輸出中會包含原始類型。
正如讀者 Kametrixom
所指出的,你還可以擴展 Contextualizable
協議并創建你自己的錯誤。(他還寫了一個非常棒的錯誤類型,可以選擇是否添加上下文。)
本文的所有代碼可以在 這個 Gist 中找到(譯者注:Gist 已經被墻,需要翻墻查看)。