176

Swift 2 の新しいエラー処理を理解しようと試みました。これが私が行ったことです。最初にエラー列挙型を宣言しました。

enum SandwichError: ErrorType {
    case NotMe
    case DoItYourself
}

そして、エラーをスローするメソッドを宣言しました (例外ではありません。エラーです)。その方法は次のとおりです。

func makeMeSandwich(names: [String: String]) throws -> String {
    guard let sandwich = names["sandwich"] else {
        throw SandwichError.NotMe
    }

    return sandwich
}

問題は呼び出し側にあります。このメソッドを呼び出すコードは次のとおりです。

let kitchen = ["sandwich": "ready", "breakfeast": "not ready"]

do {
    let sandwich = try makeMeSandwich(kitchen)
    print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
    print("Not me error")
} catch SandwichError.DoItYourself {
    print("do it error")
}

do行コンパイラが言った後Errors thrown from here are not handled because the enclosing catch is not exhaustiveSandwichErrorしかし、私の意見では、 enumには 2 つのケースしかないため、網羅的です。

通常の switch ステートメントの場合、swift は、すべてのケースを処理するときに網羅的であることを理解できます。

4

6 に答える 6

294

Swift 2 のエラー処理モデルには、網羅性と回復力という 2 つの重要なポイントがあります。まとめると、do/catchステートメントは、スローできることがわかっているエラーだけでなく、考えられるすべてのエラーをキャッチする必要があります。

関数がスローできるエラーの種類は宣言せず、スローするかどうかのみを宣言することに注意してください。これはゼロ 1 無限の問題です。他の人 (将来の自分を含む) が使用する関数を定義する人として、関数のすべてのクライアントを実装のすべての変更に適応させる必要はありません。どのようなエラーをスローするかを含めて、関数。関数を呼び出すコードは、そのような変更に対して回復力がある必要があります。

関数はスローする (または将来スローする可能性のある) エラーの種類を判断できないため、catchエラーをキャッチするブロックは、スローする可能性のあるエラーの種類を認識できません。したがって、知っているエラー タイプを処理するだけでなく、ユニバーサルcatchステートメントを使用して、そうでないエラー タイプを処理する必要があります。そうすれば、関数が将来スローするエラーのセットを変更した場合でも、呼び出し元は引き続きそのエラーをキャッチします。エラー。

do {
    let sandwich = try makeMeSandwich(kitchen)
    print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
    print("Not me error")
} catch SandwichError.DoItYourself {
    print("do it error")
} catch let error {
    print(error.localizedDescription)
}

しかし、それだけではありません。このレジリエンスのアイデアについてもう少し考えてみてください。サンドイッチを設計した方法では、エラーを使用するすべての場所でエラーを説明する必要があります。つまり、エラーケースのセットを変更するたびに、それらを使用するすべての場所を変更する必要があります...あまり面白くありません.

独自のエラー タイプを定義する背後にある考え方は、そのようなものを一元化できるようにすることです。descriptionエラーのメソッドを定義できます。

extension SandwichError: CustomStringConvertible {
    var description: String {
        switch self {
            case NotMe: return "Not me error"
            case DoItYourself: return "Try sudo"
        }
    }
}

次に、エラー処理コードでエラー タイプにそれ自体の説明を求めることができます。これで、エラーを処理するすべての場所で同じコードを使用でき、将来発生する可能性のあるエラー ケースも処理できます。

do {
    let sandwich = try makeMeSandwich(kitchen)
    print("i eat it \(sandwich)")
} catch let error as SandwichError {
    print(error.description)
} catch {
    print("i dunno")
}

これにより、エラーの種類 (またはその拡張機能) がエラーを報告する他の方法をサポートする道が開かれますUIAlertController

于 2015-06-08T23:44:10.197 に答える
30

これはまだ適切に実装されていないだけだと思います。Swift Programming Guideは、コンパイラーが「switch ステートメントのように」徹底的な一致を推論できることを暗示しているようです。catch網羅的であるために将軍が必要であることについては言及していません。

また、エラーがブロックの最後ではなく行にあることに気付くでしょう。tryつまり、ある時点で、コンパイラはtry、ブロック内のどのステートメントに未処理の例外タイプがあるかを特定できるようになります。

ただし、ドキュメントは少しあいまいです。私は「What's new in Swift」ビデオをざっと見ましたが、手がかりが見つかりませんでした。がんばります。

アップデート:

現在、ベータ 3 まで進んでおり、ErrorType 推論のヒントはありません。これが計画されていた場合 (そして、ある時点で計画されていたと今でも考えています)、プロトコル拡張の動的ディスパッチがおそらくそれを台無しにしたと私は信じています。

ベータ 4 アップデート:

Xcode 7b4 では、ドキュメント コメントのサポートが追加されましたThrows:。これは、「スローされる可能性のあるエラーとその理由を文書化するために使用する必要があります」。これにより、少なくともAPI コンシューマーにエラーを伝えるメカニズムが提供されると思います。ドキュメントがあれば型システムは必要ありません。

別の更新:

自動推論を期待して時間を費やしErrorType、そのモデルの制限が何であるかを調べた後、私は考えを変えました -これが Apple が代わりに実装することを望んでいるものです. 基本的に:

// allow us to do this:
func myFunction() throws -> Int

// or this:
func myFunction() throws CustomError -> Int

// but not this:
func myFunction() throws CustomErrorOne, CustomErrorTwo -> Int

さらに別のアップデート

Apple のエラー処理の根拠は、ここで入手できるようになりました。また、 swift-evolutionメーリング リストでも興味深い議論が行われています。本質的に、John McCall は型付きエラーに反対しています。彼は、ほとんどのライブラリが最終的に一般的なエラー ケースを含むことになり、型付きエラーがボイラープレート以外のコードに多くを追加する可能性は低いと考えているためです (彼は「野心的なはったり」という用語を使用しました)。Chris Lattner 氏は、Swift 3 がレジリエンス モデルで動作する場合、タイプされたエラーに対してオープンであると述べました。

于 2015-06-12T10:16:34.883 に答える