Swiftのスローと再スローの違いは何ですか?


83

それを把握するためにいくつかの参照を検索した後、私は間の違いを理解に関する有用な-and simple-説明を見つけることができませんでした-unfortunately-throwsとをrethrows。それらをどのように使用すべきかを理解しようとすると、ちょっと混乱します。

私はthrows、次のように、エラーを伝播するための最も単純な形式の-default-にある程度精通していることを述べておきます。

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

回答:


185

Swiftの本の「宣言」から:

関数とメソッドの再スロー

関数またはメソッドを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として宣言された場合は、例1でも呼び出す必要があります。これは「不便」であり、コードが不要になります。throwsrethrowstry
  • それmapなしで宣言された場合throws/rethrows、例2のようにスロークロージャで呼び出すことはできません。

:同じことが関数のパラメータを取るスウィフト標準ライブラリから他の方法についても同様ですfilter()index(where:)forEach()および多くのより多くの。

あなたの場合、

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

は、スローしない引数で呼び出された場合でもエラーをスローできる関数を示しますが、

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

スロー引数を指定して呼び出された場合にのみエラーをスローする関数を示します。

大まかに言えば、rethrows「それ自体で」エラーをスローするのではなく、関数パラメータから「転送」エラーのみをスローする関数用です。


37
最後の文は金色です!
クラース2017

1
@Honey:答えの最後の文は、私がそれをどのように要約するかです。
マーティンR

ええ、それは良いようです。rethrowsは、必要がないことを除いて、クロージャーでのみ使用されると言うのは正しいでしょうか?
ハニー

3
@ハニー:私はあなたが言っていることを完全には理解していません。rethrowsスローする可能性のある関数パラメーターを受け取る関数でのみ使用されます。
マーティンR

両方を行うと、構文はどうなりますか?🤔🤔それは「スローを投げ直す」でしょうか??
KautsyaKanu20年

14

マーティンの答えと一緒に何かを追加するだけです。スローイング関数と同じシグネチャを持つ非スローイング関数は、スローイング関数の1つと見なされsub-typeます。そのため、再スローはそれがどれであるかを判別できtry、func paramもスローする場合にのみ必要ですが、スローしないのと同じ関数シグネチャを受け入れます。これは、funcparamがスローされたときにdotryブロックを使用するだけでよい便利な方法ですが、関数内の他のコードはエラーをスローしません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.