Swift 與 Objective-C

Swift throws 與 Result:保留失敗原因的輸入處理

比較try?合併成nil的兩種錯誤,透過typed throws與Result保留原因,再用get取回成功值或重新拋出失敗。

閱讀 2 分鐘
Swift throws 與 Result:保留失敗原因的輸入處理 封面圖

不同失敗需要不同處理時,應用throws或Result保留原因,而不是用try?抹去。throws沿呼叫流程傳遞錯誤;Result把成功或失敗存成值,供稍後處理。

原理與設計判斷

ParseError區分非數字輸入與負數。throws(ParseError)明確指定錯誤型別,do-catch便可據此選擇回應。try?將兩種失敗都變成nil,當復原政策不同時,這樣的資訊不夠。 第一手資料

重現程式碼

將cat、-1、0、42交給同一個解析器。先確認try?讓兩種失敗都得到nil,再把結果存為Result<Int, ParseError>。typed do區塊明確指定catch的錯誤型別,get則取回成功值或重新拋出失敗。

這個獨立範例已於 2026-10-23 使用 Apple Swift 6.4,以 Swift 6 語言模式在 arm64 macOS 目標環境執行。不需要網路或額外套件。

下載完整 Swift 檔案

請在下載檔案的資料夾執行。檢查不符時,precondition 會中止程式。請勿使用 -Ounchecked,因為它會移除這些檢查。

swift -swift-version 6 swift-error-handling-throws-result.swift
enum ParseError: Error, Equatable { case notInteger, negative }
func parse(_ raw: String) throws(ParseError) -> Int {
    guard let value = Int(raw) else { throw .notInteger }
    guard value >= 0 else { throw .negative }
    return value
}

precondition((try? parse("cat")) == nil && (try? parse("-1")) == nil)
let results: [Result<Int, ParseError>] = ["cat", "-1", "0", "42"].map { raw in
    do throws(ParseError) { return .success(try parse(raw)) }
    catch { return .failure(error) }
}
precondition(results == [.failure(.notInteger), .failure(.negative), .success(0), .success(42)])
do {
    _ = try results[1].get()
    preconditionFailure("failure was lost")
} catch ParseError.negative {}
let recovered = try results[3].get()
precondition(recovered == 42)
print("try?-failures=nil,nil result=notInteger,negative,0,42 get-error=negative")

執行結果與解讀

try?-failures=nil,nil result=notInteger,negative,0,42 get-error=negative

結果陣列分別保留notInteger、negative、0、42。對失敗結果呼叫get會再次拋出negative,成功結果則得到42。這項錯誤資訊保留驗證不需要網路或檔案I/O。

適用範圍與限制

throws不能捕捉所有程式失敗。強制解包或precondition違反造成的陷阱不在此契約內,try!失敗也不應作為正常復原路徑。本實驗只執行同步解析,未驗證非同步取消、重試或檔案錯誤。

接下來要確認的事

依呼叫端需要採取的不同行動定義錯誤。單純缺值可用Optional;傳遞原因用throws;儲存或彙整結果用Result。UI提示與日誌適合在保留真實原因的邊界接上。

延伸實驗

來源與驗證