エラー処理
日本語を消す 英語を消す下記URLから引用し、日本語訳をつけてみました。
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/errorhandling
Respond to and recover from errors.
エラーに応答し、エラーから回復します。
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.
エラー処理は、プログラム内のエラー状態に応答して回復するプロセスです。 Swift は、実行時に回復可能なエラーをスロー、キャッチ、伝播、および操作するための最上級のサポートを提供します。
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(Link:developer.apple.com).
Swift のエラー処理は、Cocoa および Objective-C の NSError
クラスを使用するエラー処理パターンと相互運用します。 このクラスの詳細については、「Swift での Cocoa エラーの処理(Link:developer.apple.com)(英語)」を参照してください。
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.
Swift では、エラーは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:
Swift 列挙は、関連する値を使用して、エラーの性質に関する追加情報を伝達できるため、関連するエラー条件のグループをモデル化するのに特に適しています。 たとえば、ゲーム内で自動販売機を操作する際のエラー状態を表す方法は次のとおりです。
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.
Swift でエラーを処理するには 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.
Swift でのエラー処理は、try
、catch
、throw
キーワードを使用する他の言語の例外処理に似ています。 Objective-C を含む多くの言語の例外処理とは異なり、Swift のエラー処理には、計算コストがかかる可能性があるコール スタックの巻き戻しが含まれません。 そのため、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
でマークされた関数は、スロー関数と呼ばれます。 関数で戻り値の型を指定する場合は、return 矢印 (->
) の前に 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
クラスには、リクエストされた商品が入手できない場合、在庫切れである場合、またはコストが現在の入金額を超える場合に、適切な VendingMachineError
をスローする Vend(itemNamed:)
メソッドがあります。
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
句と照合され、どれでエラーを処理できるかが判断されます。
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."
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
句によって捕捉され、ローカルのエラー定数にバインドされます。 エラーがスローされない場合は、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:
複数の関連エラーをキャッチするもう 1 つの方法は、キャッチの後にカンマで区切ってリストすることです。 例えば:
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")
↓6.0
Specifying the Error Type
エラータイプの指定
All of the examples above use the most common kind of error handling, where the errors that your code throws can be values of any type that conforms to the Error
protocol. This approach matches the reality that you don’t know ahead of time every error that could happen while the code is running, especially when propagating errors thrown somewhere else. It also reflects the fact that errors can change over time. New versions of a library — including libraries that your dependencies use — can throw new errors, and the rich complexity of real-world user configurations can expose failure modes that weren’t visible during development or testing. The error handling code in the examples above always includes a default case to handle errors that don’t have a specific catch
clause.
上記の例はすべて、最も一般的な種類のエラー処理を使用しており、コードがスローするエラーは、Error
プロトコルに準拠する任意の型の値にすることができます。このアプローチは、コードの実行中に発生する可能性のあるすべてのエラーを事前に把握できないという現実と一致しており、特に他の場所でスローされたエラーを伝播する場合はそうです。また、エラーは時間の経過とともに変化する可能性があるという事実も反映しています。ライブラリの新しいバージョン (依存関係が使用するライブラリを含む) は新しいエラーをスローする可能性があり、現実世界のユーザー構成の複雑により、開発中やテスト中には見えなかった障害モードが明らかになることがあります。上記の例のエラー処理コードには、特定の catch
句を持たないエラーを処理するための default case が常に含まれています。
Most Swift code doesn’t specify the type for the errors it throws. However, you might limit code to throwing errors of only one specific type in the following special cases:
ほとんどの Swift コードでは、スローするエラーの種類を指定しません。ただし、次の特殊なケースでは、特定の 1 つの種類のエラーのみをスローするようにコードを制限できます。
- When running code on an embedded system that doesn’t support dynamic allocation of memory. Throwing an instance of
any Error
or another boxed protocol type requires allocating memory at runtime to store the error. In contrast, throwing an error of a specific type lets Swift avoid heap allocation for errors. - メモリの動的割り当てをサポートしていない組み込みシステムでコードを実行する場合。
any Error
または別のボックス化されたプロトコル タイプのインスタンスをスローするには、実行時にエラーを格納するためのメモリを割り当てる必要があります。対照的に、特定のタイプのエラーをスローすると、Swift はエラーのヒープ割り当てを回避できます。 - When the errors are an implementation detail of some unit of code, like a library, and aren’t part of the interface to that code. Because the errors come from only the library, and not from other dependencies or the library’s clients, you can make an exhaustive list of all possible failures. And because these errors are an implementation detail of the library, they’re always handled within that library.
- エラーがライブラリなどのコード ユニットの実装の詳細であり、そのコードへのインターフェイスの一部ではない場合。エラーはライブラリからのみ発生し、他の依存関係やライブラリのクライアントからは発生しないため、考えられるすべての障害の完全なリストを作成できます。また、これらのエラーはライブラリの実装の詳細であるため、常にそのライブラリ内で処理されます。
- In code that only propagates errors described by generic parameters, like a function that takes a closure argument and propagates any errors from that closure. For a comparison between propagating a specific error type and using
rethrows
, see doc:Declarations:Rethrowing-Functions-and-Methods. - クロージャ引数を受け取り、そのクロージャからエラーを伝播する関数など、ジェネリック パラメータによって記述されたエラーのみを伝播するコード内。特定のエラー タイプの伝播と
rethrows
の使用の比較については、doc:Declarations:Rethrowing-Functions-and-Methods を参照してください。
For example, consider code that summarizes ratings and uses the following error type:
たとえば、評価を要約し、次のエラー タイプを使用するコードを考えてみます。
enum StatisticsError: Error {
case noRatings
case invalidRating(Int)
}
To specify that a function throws only StatisticsError
values as its errors, you write throws(StatisticsError)
instead of only throws
when declaring the function. This syntax is also called typed throws because you write the error type after throws
in the declaration. For example, the function below throws StatisticsError
values as its errors.
関数がエラーとして StatisticsError
値のみをスローするように指定するには、関数を宣言するときに、throws
のみではなく throws(StatisticsError)
と記述します。この構文は、宣言で throws
の後にエラー タイプを記述するため、typed throws とも呼ばれます。たとえば、次の関数はエラーとして StatisticsError
値をスローします。
func summarize(_ ratings: [Int]) throws(StatisticsError) {
guard !ratings.isEmpty else { throw .noRatings }
var counts = [1: 0, 2: 0, 3: 0]
for rating in ratings {
guard rating > 0 && rating <= 3 else { throw .invalidRating(rating) }
counts[rating]! += 1
}
print("*", counts[1]!, "-- **", counts[2]!, "-- ***", counts[3]!)
}
In the code above, the summarize(_:)
function summarizes a list of ratings expressed on a scale of 1 to 3. This function throws an instance of StatisticsError
if the input isn’t valid. Both places in the code above that throw an error omit the type of the error because the function’s error type is already defined. You can use the short form, throw .noRatings
, instead of writing throw StatisticsError.noRatings
when throwing an error in a function like this.
上記のコードでは、summarize(_:)
関数が 1 から 3 のスケールで表された評価のリストを要約します。入力が有効でない場合、この関数は StatisticsError
のインスタンスをスローします。上記のコードでエラーをスローする 2 つの箇所では、関数のエラー タイプがすでに定義されているため、エラーのタイプが省略されています。このような関数でエラーをスローする場合は、throw StatisticsError.noRatings
と書く代わりに、短縮形の throw .noRatings
を使用できます。
When you write a specific error type at the start of the function, Swift checks that you don’t throw any other errors. For example, if you tried to use VendingMachineError
from examples earlier in this chapter in the summarize(_:)
function above, that code would produce an error at compile time.
関数の先頭で特定のエラー タイプを記述すると、Swift は他のエラーがスローされないことを確認します。たとえば、この章の前半の例の VendingMachineError
を上記の summarize(_:)
関数で使用しようとすると、そのコードはコンパイル時にエラーを生成します。
You can call a function that uses typed throws from within a regular throwing function:
通常の throw 関数内から、型指定された throw を使用する関数を呼び出すことができます。
func someThrowingFunction() -> throws {
let ratings = [1, 2, 3, 2, 2, 1]
try summarize(ratings)
}
The code above doesn’t specify an error type for someThrowingFunction()
, so it throws any Error
. You could also write the error type explicitly as throws(any Error)
; the code below is equivalent to the code above:
上記のコードでは、someThrowingFunction()
のエラー タイプを指定していないため、any Error
がスローされます。エラー タイプを明示的に throws(any Error)
として記述することもできます。以下のコードは上記のコードと同等です。
func someThrowingFunction() -> throws(any Error) {
let ratings = [1, 2, 3, 2, 2, 1]
try summarize(ratings)
}
In this code, someThrowingFunction()
propagates any errors that summarize(_:)
throws. The errors from summarize(_:)
are always StatisticsError
values, which is also a valid error for someThrowingFunction()
to throw.
このコードでは、someThrowingFunction()
は summarize(_:)
がスローするエラーをすべて伝播します。summarize(_:)
からのエラーは常に StatisticsError
値であり、これは someThrowingFunction()
がスローする有効なエラーでもあります。
Just like you can write a function that never returns with a return type of Never
, you can write a function that never throws with throws(Never)
:
戻り値の型を Never
にして、決して返らない関数を記述できるのと同様に、 throws(Never)
を使って、決してスローしない関数を記述できます。
func nonThrowingFunction() throws(Never) {
// ...
}
This function can’t throw because it’s impossible to create a value of type Never
to throw.
この関数は、スローする Never
型の値を作成できないため、スローできません。
In addition to specifying a function’s error type, you can also write a specific error type for a do
–catch
statement. For example:
関数のエラー タイプを指定することに加えて、do-catch
ステートメントに特定のエラー タイプを記述することもできます。例:
let ratings = []
do throws(StatisticsError) {
try summarize(ratings)
} catch {
switch error {
case .noRatings:
print("No ratings available")
case .invalidRating(let rating):
print("Invalid rating: \(rating)")
}
}
// Prints "No ratings available"
In this code, writing do throws(StatisticsError)
indicates that the do
–catch
statement throws StatisticsError
values as its errors. Like other do
–catch
statements, the catch
clause can either handle every possible error or propagate unhandled errors for some surrounding scope to handle. This code handles all of the errors, using a switch
statement with one case for each enumeration value. Like other catch
clauses that don’t have a pattern, the clause matches any error and binds the error to a local constant named error
. Because the do
–catch
statement throws StatisticsError
values, error
is a value of type StatisticsError
.
このコードでは、do throws(StatisticsError)
と記述することで、do-catch
文がエラーとして StatisticsError
値をスローすることを示しています。他の do-catch
文と同様に、catch
節はすべてのエラーを処理することも、未処理のエラーを周囲のスコープに伝播させて処理することもできます。このコードは、列挙値ごとに 1 つのケースを持つ switch
文を使用して、すべてのエラーを処理します。パターンを持たない他の catch
節と同様に、節はすべてのエラーに一致し、error
という名前のローカル定数にエラーをバインドします。do-catch
文は StatisticsError
値をスローするため、error
は StatisticsError
型の値です。
The catch
clause above uses a switch
statement to match and handle each possible error. If you tried to add a new case to StatisticsError
without updating the error-handling code, Swift would give you an error because the switch
statement wouldn’t be exhaustive anymore. For a library that catches all of its own errors, you could use this approach to ensure any new errors get corresponding new code to handle them.
上記の catch
句は、switch
文を使用して、起こり得る各エラーを照合して処理します。エラー処理コードを更新せずに StatisticsError
に新しいケースを追加しようとすると、switch
文が網羅的でなくなるため、Swift はエラーを返します。独自のエラーをすべてキャッチするライブラリの場合は、この方法を使用して、新しいエラーに対応する新しいコードが処理されるようにすることができます。
If a function or do
block throws errors of only a single type, Swift infers that this code is using typed throws. Using this shorter syntax, you could write the do
–catch
example above as follows:
関数または do
ブロックが単一の型のエラーのみをスローする場合、Swift はこのコードが型指定された throw
を使用していると推測します。この短い構文を使用すると、上記の do-catch
の例を次のように記述できます。
let ratings = []
do {
try summarize(ratings)
} catch {
switch error {
case .noRatings:
print("No ratings available")
case .invalidRating(let rating):
print("Invalid rating: \(rating)")
}
}
// Prints "No ratings available"
Even though the do
–catch
block above doesn’t specify what type of error it throws, Swift infers that it throws StatisticsError
. You can explicitly write throws(any Error)
to avoid letting Swift infer typed throws.
上記の do-catch
ブロックでは、スローするエラーの種類を指定していませんが、Swift は StatisticsError
をスローすると推測します。Swift が型指定された throw を推測しないようにするには、throws(any Error)
を明示的に記述します。
↑6.0
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.
}
}
The above example uses a defer
statement to ensure that the open(_:)
function has a corresponding call to close(_:)
.
上記の例では、defer
ステートメントを使用して、 open(_:)
関数に対応するclose(_:)
の呼び出しがあることを確認しています。
You can use a defer
statement even when no error handling code is involved. For more information, see Deferred Actions.
エラー処理コードが関与していない場合でも、defer
ステートメントを使用できます。 詳細については、「遅延アクション」を参照してください。