2017-04-09 68 views
21

在搜索了一些參考文獻以找出它之後,我很難找到有用的簡單描述來了解throwsrethrows之間的區別。試圖瞭解我們應該如何使用它時,這有點令人困惑。Swift中的拋出和反饋有什麼區別?

我會告訴你我有種熟悉的 - 默認throws用最簡單的傳播錯誤的形式,如下所示:

enum CustomError: Error { 
    case potato 
    case tomato 
} 

func throwCustomError(_ string: String) throws { 
    if string.lowercased().trimmingCharacters(in: .whitespaces) == "potato" { 
     throw CustomError.potato 
    } 

    if string.lowercased().trimmingCharacters(in: .whitespaces) == "tomato" { 
     throw CustomError.tomato 
    } 
} 

do { 
    try throwCustomError("potato") 
} catch let error as CustomError { 
    switch error { 
    case .potato: 
     print("potatos catched") // potatos catched 
    case .tomato: 
     print("tomato catched") 
    } 
} 

到目前爲止好,但問題出現時:

func throwCustomError(function:(String) throws ->()) throws { 
    try function("throws string") 
} 

func rethrowCustomError(function:(String) throws ->()) rethrows { 
    try function("rethrows string") 
} 

rethrowCustomError { string in 
    print(string) // rethrows string 
} 

try throwCustomError { string in 
    print(string) // throws string 
} 

我所知道的,到目前爲止是調用一個throws它必須由try處理,不像rethrows函數時。所以呢?!當決定使用throwsrethrows時,我們應遵循什麼邏輯?

回答

57

"Declarations"在斯威夫特書:

重新拋出函數和方法

一個函數或方法可以與rethrows關鍵字 聲明表明,它拋出一個錯誤只有一個它的功能 參數會引發錯誤。這些功能和方法被稱爲 重新拋光功能重新拋光方法。回滾函數和 方法必須至少有一個拋出函數參數。

一個典型的例子是map方法:

public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T] 

如果map被稱爲具有非拋變換,它不會引發 錯誤本身,並且可以被稱爲無try

// Example 1: 

let a = [1, 2, 3] 

func f1(n: Int) -> Int { 
    return n * n 
} 

let a1 = a.map(f1) 

但是,如果map被調用了投擲閉包,那麼它本身可以拋出 d必須try被稱爲:

// Example 2: 

let a = [1, 2, 3] 
enum CustomError: Error { 
    case illegalArgument 
} 

func f2(n: Int) throws -> Int { 
    guard n >= 0 else { 
     throw CustomError.illegalArgument 
    } 
    return n*n 
} 


do { 
    let a2 = try a.map(f2) 
} catch { 
    // ... 
} 
  • 如果map被宣佈爲throws代替rethrows那麼你就 甚至已經在例1 try稱呼它, 這是「不方便」和醃代碼不必要。
  • 如果map被聲明沒有throws/rethrows那麼你不能用 用例2中的拋出閉包來調用它。

同樣是從雨燕標準庫 內搭功能參數的其他方法一樣:filter()index(where:)forEach()和許多許多。

在你的情況,

func throwCustomError(function:(String) throws ->()) throws 

表示功能,可以拋出一個錯誤,即使調用 非投擲的說法,而

func rethrowCustomError(function:(String) throws ->()) rethrows 

表示這將引發錯誤的函數只有在調用 的投擲參數時纔有效。

粗略地講,rethrows是不「靠自己」扔 錯誤的功能,但只有「前進」的錯誤,從它們的功能 參數。

+1

很好的回答。謝謝。 – Darko

+3

最後一句話是金色的! – Klaas

+1

所以我想總結一下,當你*可能會拋出時'重新拋出'。當你想**限制爲總是投擲時投擲''' – Honey

7

只是添加了一些與馬丁的答案。具有與投擲功能相同簽名的非投擲功能被認爲是投擲功能的sub-type。這就是爲什麼rethrows可以決定它是哪一個,並且只有當func param也拋出時才需要try,但仍然接受不拋出的相同函數簽名。當func參數拋出時,只需要使用do try塊就是一種方便的方法,但函數中的其他代碼不會引發錯誤。

相關問題