それを理解するためにいくつかの参照を検索した後、残念ながら、throws
とrethrows
の違いを理解するのに役立つ-簡単な説明が見つかりませんでした。それらをどのように使用すべきかを理解しようとすると、一種の混乱を招きます。
次のように、エラーを伝播するための最も単純な形式の-default- 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
関数を呼び出すときです。だから何?! throws
またはrethrows
の使用を決定する際に従うべきロジックは何ですか?
Swift本の "Declarations" から:
関数とメソッドの再スロー
関数またはメソッドを
rethrows
キーワードで宣言して、関数のパラメーターの1つがエラーをスローした場合にのみエラーをスローすることを示すことができます。これらの関数とメソッドは、再スロー関数および再スローメソッドとして知られています。再スローする関数とメソッドには、少なくとも1つのスロー関数パラメーターが必要です。
典型的な例は 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
がスローするクロージャーで呼び出される場合、それ自体がスローでき、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のようにスローするクロージャーで呼び出すことはできません。同じことが、関数パラメーターを受け取るSwift標準ライブラリの他のメソッドにも当てはまります:filter()
、index(where:)
、forEach()
など。
あなたの場合、
func throwCustomError(function:(String) throws -> ()) throws
は、非スロー引数で呼び出された場合でもエラーをスローできる関数を示しますが、
func rethrowCustomError(function:(String) throws -> ()) rethrows
throwing引数を指定して呼び出された場合にのみエラーをスローする関数を示します。
大まかに言うと、rethrows
は、「独自に」エラーをスローするのではなく、関数パラメーターから「フォワード」エラーのみをスローする関数用です。
マーティンの答えと一緒に何かを追加するだけです。スロー機能と同じシグネチャを持つ非スロー機能は、スロー機能のsub-type
と見なされます。これが、再スローがそれがどれであるかを決定し、func paramもスローするときにtry
のみを必要とするが、スローしない同じ関数シグネチャを受け入れることができる理由です。 func paramがスローされたときにのみdo tryブロックを使用する必要がある便利な方法ですが、関数内の他のコードはエラーをスローしません。