Error Handling¶ エラーの処理¶
Error handling is the process of responding to and recovering from error conditions in your program. Swift provides first-class support for throwing, catching, propagating, and manipulating recoverable errors at runtime. エラー処理は、あなたのプログラムにおいてエラー状態へ応答してそこから復旧する過程です。スウィフトは、回復可能なエラーのスロー、キャッチ、伝達、そして取り扱いに対してファーストクラスのサポートを提供します。
Some operations aren’t guaranteed to always complete execution or produce a useful output. Optionals are used to represent the absence of a value, but when an operation fails, it’s often useful to understand what caused the failure, so that your code can respond accordingly. いくつかの操作は、常に実行を完了することや役に立つ出力を生成することを保証されません。オプショナルは、ある値の欠如を表すために使われます、しかしある操作が失敗する時、何がその失敗をもたらしたのか理解するのはしばしば役に立ちます、それであなたのコードはそれに適切に応答することができます。
As an example, consider the task of reading and processing data from a file on disk. There are a number of ways this task can fail, including the file not existing at the specified path, the file not having read permissions, or the file not being encoded in a compatible format. Distinguishing among these different situations allows a program to resolve some errors and to communicate to the user any errors it can’t resolve. ひとつの例として、ディスク上のファイルからデータを読み込んで処理する作業を考えてみてください。この作業が失敗するたくさんの道筋があります、そのファイルが指定したパスで存在しない、ファイルが読み出し権限を持っていない、またはファイルが互換性のある形式で符号化されていないことを含めて。これらの異なった状況を区別することは、プログラムにいくらかのエラーを解消すること、そしてなんらかのそれが解消できないエラーを利用者に伝えることを可能にします。
Note 注意
Error handling in Swift interoperates with error handling patterns that use the NSError
class in Cocoa and Objective-C. For more information about this class, see Handling Cocoa Errors in Swift.
スウィフトでのエラー処理は、CocoaとObjective-CでのNSError
クラスを使うエラー処理パターンと相互運用性があります。このクラスについてのさらなる情報として、CocoaエラーをSwiftにおいて処理するを見てください。
Representing and Throwing Errors¶ エラーの表現とスロー¶
In Swift, errors are represented by values of types that conform to the Error
protocol. This empty protocol indicates that a type can be used for error handling.
スウィフトでは、エラーはError
プロトコルに準拠する型の値によって表されます。この空のプロトコルは、ある型がエラー処理のために使われることができるのを示します。
Swift enumerations are particularly well suited to modeling a group of related error conditions, with associated values allowing for additional information about the nature of an error to be communicated. For example, here’s how you might represent the error conditions of operating a vending machine inside a game: スウィフト列挙は、あるエラーの性質についての追加情報が通信されるのを想定した関連値を含め、関係のあるエラー状況のグループを作るのにうってつけです。例えば、ここにあなたが表すかもしれないあるゲーム内の自動販売機操作のエラー状況がどのようなものかがあります:
- enum VendingMachineError: Error {
- case invalidSelection
- case insufficientFunds(coinsNeeded: Int)
- case outOfStock
- }
Throwing an error lets you indicate that something unexpected happened and the normal flow of execution can’t continue. You use a throw
statement to throw an error. For example, the following code throws an error to indicate that five additional coins are needed by the vending machine:
エラーのスローがあなたに示すのは、何か予期せぬことが起こった、そして通常の実行の流れは続けることができないということです。あなたはthrow
文を使ってエラーをスローします。例えば、以下のコードはあるエラーをスローして、5つの追加のコインが自動販売機に必要とされることを示します。
- throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
Handling Errors¶ エラーを処理する¶
When an error is thrown, some surrounding piece of code must be responsible for handling the error—for example, by correcting the problem, trying an alternative approach, or informing the user of the failure. あるエラーがスローされるとき、なかには周囲のコード部分がエラーを処理することに対して責任を持たなければならないこともあります ― 例えば、問題を訂正すること、代わりの取り組みを試みること、または失敗をユーザに知らせることによって。
There are four ways to handle errors in Swift. You can propagate the error from a function to the code that calls that function, handle the error using a do
-catch
statement, handle the error as an optional value, or assert that the error will not occur. Each approach is described in a section below.
4つの方法がエラーを取り扱うためにスウィフトにはあります。あなたは、エラーを関数からその関数を呼び出しているコードに伝えて、そのエラーをdo
-catch
文を使って取り扱う、エラーをオプショナルとして取り扱う、またはそのエラーは起こらないことを表明することができます。各取り組みは、以下の節で記述されます。
When a function throws an error, it changes the flow of your program, so it’s important that you can quickly identify places in your code that can throw errors. To identify these places in your code, write the try
keyword—or the try?
or try!
variation—before a piece of code that calls a function, method, or initializer that can throw an error. These keywords are described in the sections below.
ある関数がエラーをスローするとき、それはあなたのプログラムの流れを変えます、そのため重要なのは、あなたがすばやくあなたのコードの中のエラーをスローできる場所を識別することです。これらの場所をあなたのコードの中で識別するには、try
キーワードを ― またはその変種try?
またはtry!
を ― エラーをスローできる関数、メソッド、またはイニシャライザを呼び出すコードの前の場所に書いてください。これらのキーワードは、以下の節で解説されます。
Note 注意
Error handling in Swift resembles exception handling in other languages, with the use of the try
, catch
and throw
keywords. Unlike exception handling in many languages—including Objective-C—error handling in Swift doesn’t involve unwinding the call stack, a process that can be computationally expensive. As such, the performance characteristics of a throw
statement are comparable to those of a return
statement.
スウィフトにおけるエラー処理は、try
、catch
、そしてthrow
キーワードの使用とともに、他の言語での例外処理に似ています。多くの言語 ― Objective-Cを含めて ― での例外処理と違い、スウィフトにおけるエラー処理はコールスタック、計算的に高くつく可能性がある処理、の巻き戻し(アンワインド)を必要としません。throw
文のいろいろな性能特徴は、それ自体としては、return
文のそれと同程度です。
Propagating Errors Using Throwing Functions¶ スロー関数を使ってエラーを伝える¶
To indicate that a function, method, or initializer can throw an error, you write the throws
keyword in the function’s declaration after its parameters. A function marked with throws
is called a throwing function. If the function specifies a return type, you write the throws
keyword before the return arrow (->
).
エラーをスローすることのできる関数、メソッド、またはイニシャライザを指し示すために、あなたはthrows
キーワードを関数の定義においてそれのパラメータの後に書きます。throws
で印された関数は、スロー関数と呼ばれます。その関数が戻り型を指定するならば、あなたはthrows
キーワードを戻り矢印(->
)の前に書きます。
- func canThrowErrors() throws -> String
- func cannotThrowErrors() -> String
A throwing function propagates errors that are thrown inside of it to the scope from which it’s called. スロー関数は、それの内部でスローされるエラーを、そこからそれが呼び出されるスコープへと伝えます。
Note 注意
Only throwing functions can propagate errors. Any errors thrown inside a nonthrowing function must be handled inside the function. スロー関数だけがエラーを伝えることができます。スローしない関数の内部でスローされるどんなエラーも、その関数の内部で取り扱われなければなりません。
In the example below, the VendingMachine
class has a vend(itemNamed:)
method that throws an appropriate VendingMachineError
if the requested item isn’t available, is out of stock, or has a cost that exceeds the current deposited amount:
下の例において、VendingMachine
クラスはvend(itemNamed:)
メソッドを持ちます、それは、要求された項目が利用可能でない、在庫切れ、または現在預け入れされた総額を超える価格を持つならば対応するVendingMachineError
をスローします:
- struct Item {
- var price: Int
- var count: Int
- }
- class VendingMachine {
- var inventory = [
- "Candy Bar": Item(price: 12, count: 7),
- "Chips": Item(price: 10, count: 4),
- "Pretzels": Item(price: 7, count: 11)
- ]
- var coinsDeposited = 0
- func vend(itemNamed name: String) throws {
- guard let item = inventory[name] else {
- throw VendingMachineError.invalidSelection
- }
- guard item.count > 0 else {
- throw VendingMachineError.outOfStock
- }
- guard item.price <= coinsDeposited else {
- throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
- }
- coinsDeposited -= item.price
- var newItem = item
- newItem.count -= 1
- inventory[name] = newItem
- print("Dispensing \(name)")
- }
- }
The implementation of the vend(itemNamed:)
method uses guard
statements to exit the method early and throw appropriate errors if any of the requirements for purchasing a snack aren’t met. Because a throw
statement immediately transfers program control, an item will be vended only if all of these requirements are met.
vend(itemNamed:)
メソッドの実装はguard
文を使って、購入スナックに必要な何かが満たされないならば早めにそのメソッドを終了して対応するエラーをスローします。throw
文が直ちにプログラム制御を移すので、これらの必要なものすべてが満たされる場合にのみ項目は販売されることになります。
Because the vend(itemNamed:)
method propagates any errors it throws, any code that calls this method must either handle the errors—using a do
-catch
statement, try?
, or try!
—or continue to propagate them. For example, the buyFavoriteSnack(person:vendingMachine:)
in the example below is also a throwing function, and any errors that the vend(itemNamed:)
method throws will propagate up to the point where the buyFavoriteSnack(person:vendingMachine:)
function is called.
このvend(itemNamed:)
メソッドはそれがスローするどんなエラーも伝達するので、このメソッドを呼び出す何らかのコードは、それらのエラーを取り扱うか ― do
-catch
文、try?
、またはtry!
を使って ― またはそれらの伝達を続けるか、どちらかをしなければなりません。たとえば、下の例のbuyFavoriteSnack(person:vendingMachine:)
もまたスロー関数です、そしてvend(itemNamed:)
メソッドがスローするあらゆるエラーは、buyFavoriteSnack(person:vendingMachine:)
関数が呼び出される地点へとさかのぼり伝えられます。
- let favoriteSnacks = [
- "Alice": "Chips",
- "Bob": "Licorice",
- "Eve": "Pretzels",
- ]
- func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
- let snackName = favoriteSnacks[person] ?? "Candy Bar"
- try vendingMachine.vend(itemNamed: snackName)
- }
In this example, the buyFavoriteSnack(person: vendingMachine:)
function looks up a given person’s favorite snack and tries to buy it for them by calling the vend(itemNamed:)
method. Because the vend(itemNamed:)
method can throw an error, it’s called with the try
keyword in front of it.
この例において、buyFavoriteSnack(person: vendingMachine:)
関数は指定された個人のお気に入りのスナックを探してそれを彼らのために仕入れることをvend(itemNamed:)
メソッドを呼ぶことによって試みます。vend(itemNamed:)
メソッドはエラーをスローできることから、それはそれの前のtry
キーワードとともに呼び出されます。
Throwing initializers can propagate errors in the same way as throwing functions. For example, the initializer for the PurchasedSnack
structure in the listing below calls a throwing function as part of the initialization process, and it handles any errors that it encounters by propagating them to its caller.
スローするイニシャライザは、スローする関数と同じ方法でエラーを伝達できます。例えば、以下のコード出力のPurchasedSnack
構造体のためのイニシャライザは、スロー関数を初期化処理の一部として呼び出します、そしてそれは、それが遭遇するどんなエラーもそれの呼び出し側にそれらを伝達することによって取り扱います。
- struct PurchasedSnack {
- let name: String
- init(name: String, vendingMachine: VendingMachine) throws {
- try vendingMachine.vend(itemNamed: name)
- self.name = name
- }
- }
Handling Errors Using Do-Catch¶ do-catchを使ってエラーを処理する¶
You use a do
-catch
statement to handle errors by running a block of code. If an error is thrown by the code in the do
clause, it’s matched against the catch
clauses to determine which one of them can handle the error.
あなたは、あるコードの塊を実行することによってエラーを処理するために、do
-catch
文を使います。あるエラーがdo
節の中にあるコードによってスローされるならば、それはcatch
節と照合されて、それらの1つがそのエラーを処理できると決定されます。
Here is the general form of a do
-catch
statement:
ここにdo
-catch
文の一般的な形式があります:
- do {
- try expression
- statements
- } catch pattern 1 {
- statements
- } catch pattern 2 where condition {
- statements
- } catch pattern 3, pattern 4 where condition {
- statements
- } catch {
- statements
- }
You write a pattern after catch
to indicate what errors that clause can handle. If a catch
clause doesn’t have a pattern, the clause matches any error and binds the error to a local constant named error
. For more information about pattern matching, see Patterns.
あなたは、catch
の後にあるパターンを書いてどんなエラーをその節が取り扱えるかを指し示します。catch
節がパターンを持たないならば、その節はあらゆるエラーにマッチします、そしてそのエラーをerror
と名前を付けられるローカル定数に束縛します。パターンマッチングについての更なる情報として、パターンを見てください。
For example, the following code matches against all three cases of the VendingMachineError
enumeration.
例えば、以下のコードはVendingMachineError
列挙の3つのケース節すべてに対して適合します。
- var vendingMachine = VendingMachine()
- vendingMachine.coinsDeposited = 8
- do {
- try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
- print("Success! Yum.")
- } catch VendingMachineError.invalidSelection {
- print("Invalid Selection.")
- } catch VendingMachineError.outOfStock {
- print("Out of Stock.")
- } catch VendingMachineError.insufficientFunds(let coinsNeeded) {
- print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
- } catch {
- print("Unexpected error: \(error).")
- }
- // Prints "Insufficient funds. Please insert an additional 2 coins."(「金額が不足しています。さらに2コイン入れてください。」を出力します)
In the above example, the buyFavoriteSnack(person:vendingMachine:)
function is called in a try
expression, because it can throw an error. If an error is thrown, execution immediately transfers to the catch
clauses, which decide whether to allow propagation to continue. If no pattern is matched, the error gets caught by the final catch
clause and is bound to a local error
constant. If no error is thrown, the remaining statements in the do
statement are executed.
上の例において、buyFavoriteSnack(person:vendingMachine:)
関数はtry
式の中で呼び出されます、それがエラーをスローできるからです。エラーがスローされるならば、実行は直ちにcatch
節に移ります、それは伝達を継続させるかどうか結論を下します。パターンが適合することが全く無いならば、エラーは最後のcatch
節によってキャッチされて、あるローカルerror
定数に束縛されます。エラーがスローされることが全く無いならば、do
文に残っている文が遂行されます。
The catch
clauses don’t have to handle every possible error that the code in the do
clause can throw. If none of the catch
clauses handle the error, the error propagates to the surrounding scope. However, the propagated error must be handled by some surrounding scope. In a nonthrowing function, an enclosing do
-catch
statement must handle the error. In a throwing function, either an enclosing do
-catch
statement or the caller must handle the error. If the error propagates to the top-level scope without being handled, you’ll get a runtime error.
catch
節は、do
節の中のコードがスロー可能なすべての起こりうるエラーを取り扱う必要はありません。どのcatch
節もエラーを処理しないならば、エラーは周囲のスコープへと伝えられます。しかしながら、伝えられるエラーは周囲のスコープの何れかによって処理される必要があります。非スロー関数では、取り囲んでいるdo
-catch
文がエラーを処理しなければなりません。スロー関数では、取り囲んでいるdo
-catch
文または呼び出し側のどちらかがエラーを処理しなければなりません。エラーが取り扱われることなくトップレベルスコープに伝わるならば、あなたは実行時エラーを得るでしょう。
For example, the above example can be written so any error that isn’t a VendingMachineError
is instead caught by the calling function:
例えば、上の例はVendingMachineError
でないあらゆるエラーが、呼び出し側の関数によって代わりにキャッチされるように書かれることができます:
- func nourish(with item: String) throws {
- do {
- try vendingMachine.vend(itemNamed: item)
- } catch is VendingMachineError {
- print("Couldn't buy that from the vending machine.")
- }
- }
- do {
- try nourish(with: "Beet-Flavored Chips")
- } catch {
- print("Unexpected non-vending-machine-related error: \(error)")
- }
- // Prints "Couldn't buy that from the vending machine."
In the nourish(with:)
function, if vend(itemNamed:)
throws an error that’s one of the cases of the VendingMachineError
enumeration, nourish(with:)
handles the error by printing a message. Otherwise, nourish(with:)
propagates the error to its call site. The error is then caught by the general catch
clause.
nourish(with:)
関数において、vend(itemNamed:)
がVendingMachineError
列挙のケース節の1つであるエラーをスローするならば、nourish(with:)
はそのエラーをメッセージを出力することによって取り扱います。そうでなければ、nourish(with:)
はそのエラーをそれの呼出地点へと伝達します。エラーは、それから一般的なcatch
節によってキャッチされます。
Another way to catch several related errors is to list them after catch
, separated by commas. For example:
いくつかの関連したエラーをキャッチする別の方法は、それらをcatch
の後に、コンマで区切って列記することになります。例えば:
- func eat(item: String) throws {
- do {
- try vendingMachine.vend(itemNamed: item)
- } catch VendingMachineError.invalidSelection, VendingMachineError.insufficientFunds, VendingMachineError.outOfStock {
- print("Invalid selection, out of stock, or not enough money.")
- }
- }
The eat(item:)
function lists the vending machine errors to catch, and its error text corresponds to the items in that list. If any of the three listed errors are thrown, this catch
clause handles them by printing a message. Any other errors are propagated to the surrounding scope, including any vending-machine errors that might be added later.
eat(item:)
関数は、自動販売機エラーそれらをリストしてキャッチします、そしてそれのエラーテキストをそのリストの中の項目と結び付けます。3つのリストされたエラーのどれかがスローされるならば、このcatch
節はそれらをあるメッセージを出力することによって取り扱います。何らかの他のエラーは、周囲のスコープに伝播されます、後で加えられるかもしれないあらゆる自動販売機エラーを含めて。
Converting Errors to Optional Values¶ エラーをオプショナルの値に変換する¶
You use try?
to handle an error by converting it to an optional value. If an error is thrown while evaluating the try?
expression, the value of the expression is nil
. For example, in the following code x
and y
have the same value and behavior:
あなたは、try?
を使って、あるエラーをオプショナルの値に変換することによって取り扱うことができます。try?
式を評価している間にエラーがスローされるならば、式の値はnil
になります。例えば、以下のコードにおいてx
とy
は、同じ値と挙動を持ちます。
- func someThrowingFunction() throws -> Int {
- // ...
- }
- let x = try? someThrowingFunction()
- let y: Int?
- do {
- y = try someThrowingFunction()
- } catch {
- y = nil
- }
If someThrowingFunction()
throws an error, the value of x
and y
is nil
. Otherwise, the value of x
and y
is the value that the function returned. Note that x
and y
are an optional of whatever type someThrowingFunction()
returns. Here the function returns an integer, so x
and y
are optional integers.
someThrowingFunction()
がエラーをスローするならば、x
とy
の値はnil
です。そうでなければ、x
とy
の値はこの関数が返す値です。x
とy
は、たとえどんなものでもsomeThrowingFunction()
が返す型のオプショナルです。ここに整数を返す関数があります、それでx
とy
はオプショナル整数です。
Using try?
lets you write concise error handling code when you want to handle all errors in the same way. For example, the following code uses several approaches to fetch data, or returns nil
if all of the approaches fail.
try?
を使うことで、あなたに簡潔なエラー処理コードを書くことを可能にするのは、あなたがすべてのエラーを同じやり方で取り扱いたい時です。例えば、以下のコードはいくつかの取り組みを使ってデータを取ってきます、またはすべての取り組みが失敗するならばnil
を返します。
- func fetchData() -> Data? {
- if let data = try? fetchDataFromDisk() { return data }
- if let data = try? fetchDataFromServer() { return data }
- return nil
- }
Disabling Error Propagation¶ エラー伝達を抑制する¶
Sometimes you know a throwing function or method won’t, in fact, throw an error at runtime. On those occasions, you can write try!
before the expression to disable error propagation and wrap the call in a runtime assertion that no error will be thrown. If an error actually is thrown, you’ll get a runtime error.
時にはあなたはあるスロー関数またはメソッドが、実際のところ、実行時にエラーをスローすることがないのを知っています。これらの場合には、あなたはtry!
をその式の前に書くことによって、エラー伝達を抑制して、エラーはスローされないという実行時表明の中にその呼び出しを包み込みます。エラーが実際はスローされるならば、あなたは実行時エラーを受け取るでしょう。
For example, the following code uses a loadImage(atPath:)
function, which loads the image resource at a given path or throws an error if the image can’t be loaded. In this case, because the image is shipped with the application, no error will be thrown at runtime, so it’s appropriate to disable error propagation.
例えば、以下のコードはloadImage(atPath:)
関数を使います、それは画像リソースを与えられたパスでロードします、または画像がロードできないならばエラーをスローします。この場合、画像はアプリケーションとともに出荷されるので、エラーが実行時にスローされることはありません、それでふさわしいのはエラー伝達を抑制することです。
- let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
Specifying Cleanup Actions¶ クリーンアップ動作の指定¶
You use a defer
statement to execute a set of statements just before code execution leaves the current block of code. This statement lets you do any necessary cleanup that should be performed regardless of how execution leaves the current block of code—whether it leaves because an error was thrown or because of a statement such as return
or break
. For example, you can use a defer
statement to ensure that file descriptors are closed and manually allocated memory is freed.
あなたはdefer
文を使うことで、コード実行が現在のコードブロックから離れる直前に一揃いの文を実行するようにします。この文は、あなたに何らかの不可欠なクリーンアップを行わせます、それはどうやって実行が現在のコードブロックから離れるか ― それがエラーがスローされたためにまたはreturn
またはbreak
のような文を理由に離れるかどうかに関係なく実行されるべきものです。例えば、あなたはdefer
文を使ってファイル記述子が閉じられて手動割り当てメモリが解放されることを確実にします。
A defer
statement defers execution until the current scope is exited. This statement consists of the defer
keyword and the statements to be executed later. The deferred statements may not contain any code that would transfer control out of the statements, such as a break
or a return
statement, or by throwing an error. Deferred actions are executed in the reverse of the order that they’re written in your source code. That is, the code in the first defer
statement executes last, the code in the second defer
statement executes second to last, and so on. The last defer
statement in source code order executes first.
defer
文は、現在のスコープが終了されるまで実行を延期します。この文は、defer
キーワードと後で実行される文から成ります。延期される文は、制御をその文の外に、例えばbreak
やreturn
文、またはエラーをスローすることによって移すいかなるコードも含んではいけません。延期された動作は、それらがあなたのソースコードに書かれた順序の逆に実行されます。すなわち、最初のdefer
文のコードが最後に実行され、2番目のdefer
文のコードが最後から2番目に実行され、等々。ソースコード順序での最後のdefer
文は最初に実行されます。
- func processFile(filename: String) throws {
- if exists(filename) {
- let file = open(filename)
- defer {
- close(file)
- }
- while let line = try file.readline() {
- // Work with the file.(ファイル処理。)
- }
- // close(file) is called here, at the end of the scope.(close(file)がここで呼ばれます、このスコープの終わりで。)
- }
- }
The above example uses a defer
statement to ensure that the open(_:)
function has a corresponding call to close(_:)
.
上の例は、defer
文を使って、open(_:)
関数がそれと対応するclose(_:)
への呼び出しを持つことを確実にします。
Note 注意
You can use a defer
statement even when no error handling code is involved.
あなたは、defer
文を使うことが、エラー処理コードを伴わない時でさえも可能です。