閉鎖
日本語を消す 英語を消す下記URLから引用し、日本語訳をつけてみました。
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures
Group code that executes together, without creating a named function.
名前付き関数を作成せずに、一緒に実行されるコードをグループ化します。
Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
クロージャ(閉鎖)は、コード内で渡して使用できる自己完結型の機能ブロックです。 Swift のクロージャは、C および Objective-C のブロック、および他のプログラミング言語のラムダに似ています。
Closures can capture and store references to any constants and variables from the context in which they’re defined. This is known as closing over those constants and variables. Swift handles all of the memory management of capturing for you.
クロージャは、定義されているコンテキストから任意の定数と変数への参照をキャプチャして保存できます。 これは、これらの定数と変数を閉じることとして知られています。 Swift はキャプチャのメモリ管理をすべて処理します。
Note
注釈
Don’t worry if you aren’t familiar with the concept of capturing. It’s explained in detail below in Capturing Values.
キャプチャの概念に慣れていなくても心配する必要はありません。 これについては、「値の取得」で詳しく説明します。
Global and nested functions, as introduced in Functions, are actually special cases of closures. Closures take one of three forms:
「関数」で紹介したグローバル関数とネストされた関数は、実際にはクロージャの特殊なケースです。 クロージャは次の 3 つの形式のいずれかを取ります。
- Global functions are closures that have a name and don’t capture any values.
- グローバル関数は名前を持ち、値をキャプチャしないクロージャです。
- Nested functions are closures that have a name and can capture values from their enclosing function.
- ネストされた関数は名前があり、それを囲んでいる関数から値を取得できるクロージャです。
- Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.
- クロージャ式は、周囲のコンテキストから値を取得できる軽量構文で記述された名前のないクロージャです。
Swift’s closure expressions have a clean, clear style, with optimizations that encourage brief, clutter-free syntax in common scenarios. These optimizations include:
Swift のクロージャ式はクリーンで明確なスタイルを持ち、一般的なシナリオで簡潔ですっきりとした構文を奨励する最適化が施されています。 これらの最適化には次のものが含まれます。
- Inferring parameter and return value types from context
- コンテキストからのパラメータと戻り値の型の推測
- Implicit returns from single-expression closures
- 単一式クロージャからの暗黙的な戻り値
- Shorthand argument names
- 引数の短縮名
- Trailing closure syntax
- 後続クロージャーの構文
Closure Expressions
クロージャ式
Nested functions, as introduced in Nested Functions, are a convenient means of naming and defining self-contained blocks of code as part of a larger function. However, it’s sometimes useful to write shorter versions of function-like constructs without a full declaration and name. This is particularly true when you work with functions or methods that take functions as one or more of their arguments.
「ネストされた関数」で紹介されているように、ネストされた関数は、より大きな関数の一部としてコードの自己完結型ブロックに名前を付けて定義する便利な手段です。 ただし、完全な宣言と名前を使用せずに、関数のような構造の短いバージョンを作成すると便利な場合があります。 これは、関数を 1 つ以上の引数として受け取る関数またはメソッドを操作する場合に特に当てはまります。
Closure expressions are a way to write inline closures in a brief, focused syntax. Closure expressions provide several syntax optimizations for writing closures in a shortened form without loss of clarity or intent. The closure expression examples below illustrate these optimizations by refining a single example of the sorted(by:)
method over several iterations, each of which expresses the same functionality in a more succinct way.
クロージャ式は、簡潔で焦点を絞った構文でインライン クロージャを記述する方法です。 クロージャ式は、明確さや意図を損なうことなく短縮形式でクロージャを記述するためのいくつかの構文の最適化を提供します。 以下のクロージャ式の例は、sorted(by:)
メソッドの 1 つの例を数回繰り返して改良することにより、これらの最適化を示しています。それぞれの例は、同じ機能をより簡潔な方法で表現しています。
The Sorted Method
ソート方法
Swift’s standard library provides a method called sorted(by:)
, which sorts an array of values of a known type, based on the output of a sorting closure that you provide. Once it completes the sorting process, the sorted(by:)
method returns a new array of the same type and size as the old one, with its elements in the correct sorted order. The original array isn’t modified by the sorted(by:)
method.
Swift の標準ライブラリは、sorted(by:)
と呼ばれるメソッドを提供します。これは、指定した並べ替えクロージャの出力に基づいて、既知の型の値の配列を並べ替えます。 並べ替えプロセスが完了すると、sorted(by:)
メソッドは、要素が正しく並べ替えられた順序で、古い配列と同じ型とサイズの新しい配列を返します。 元の配列は、sorted(by:)
メソッドによって変更されません。
The closure expression examples below use the sorted(by:)
method to sort an array of String
values in reverse alphabetical order. Here’s the initial array to be sorted:
以下のクロージャ式の例では、sorted(by:)
メソッドを使用して、String
値の配列を逆アルファベット順に並べ替えています。 ソートされる最初の配列は次のとおりです。
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
The sorted(by:)
method accepts a closure that takes two arguments of the same type as the array’s contents, and returns a Bool
value to say whether the first value should appear before or after the second value once the values are sorted. The sorting closure needs to return true
if the first value should appear before the second value, and false
otherwise.
sorted(by:)
メソッドは、配列の内容と同じ型の 2 つの引数を取るクロージャを受け入れ、値が並べ替えられた後、最初の値が 2 番目の値の前に現れるか後ろに現れるかを示すブール値を返します。 ソート クロージャは、最初の値が 2 番目の値の前に表示される場合は true
を返し、それ以外の場合は false
を返す必要があります。
This example is sorting an array of String
values, and so the sorting closure needs to be a function of type (String, String) -> Bool
.
この例は String
値の配列を並べ替えているため、並べ替えクロージャは (String, String) -> Bool
型の関数である必要があります。
One way to provide the sorting closure is to write a normal function of the correct type, and to pass it in as an argument to the sorted(by:)
method:
ソート クロージャを提供する 1 つの方法は、正しい型の通常の関数を作成し、それを引数として sorted(by:)
メソッドに渡すことです。
func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
var reversedNames = names.sorted(by: backward)
// reversedNames is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
If the first string (s1
) is greater than the second string (s2
), the backward(_:_:)
function will return true
, indicating that s1
should appear before s2
in the sorted array. For characters in strings, “greater than” means “appears later in the alphabet than”. This means that the letter "B"
is “greater than” the letter "A"
, and the string "Tom"
is greater than the string "Tim"
. This gives a reverse alphabetical sort, with "Barry"
being placed before "Alex"
, and so on.
最初の文字列 (s1
) が 2 番目の文字列 (s2
) より大きい場合、
関数は backward(_:_:)
true
を返し、並べ替えられた配列内で s1
が s2
の前に現れる必要があることを示します。 文字列内の文字の場合、「より大きい」は「アルファベットの後ろにある」ことを意味します。 これは、文字「B
」が文字「A
」より「大きく」、文字列「Tom
」が文字列「Tim
」より大きいことを意味します。 これにより、「Barry
」が「Alex
」の前に配置されるなど、逆アルファベット順に並べ替えられます。
However, this is a rather long-winded way to write what is essentially a single-expression function (a > b
). In this example, it would be preferable to write the sorting closure inline, using closure expression syntax.
ただし、これは、本質的に単一式関数 (a > b
) であるものを記述するかなり長ったらしい方法です。 この例では、クロージャ式構文を使用してソート クロージャをインラインで記述することが望ましいでしょう。
Closure Expression Syntax
クロージャ式の構文
Closure expression syntax has the following general form:
クロージャ式の構文は次の一般的な形式になります。
{ (<#parameters#>) -> <#return type#> in
<#statements#>
}
The parameters in closure expression syntax can be in-out parameters, but they can’t have a default value. Variadic parameters can be used if you name the variadic parameter. Tuples can also be used as parameter types and return types.
クロージャ式構文のパラメータは入出力パラメータにすることができますが、デフォルト値を持つことはできません。 可変個引数パラメーターに名前を付けると、可変個引数パラメーターを使用できます。 タプルはパラメータの型や戻り値の型としても使用できます。
The example below shows a closure expression version of the backward(_:_:)
function from above:
以下の例は、上記の backward(_:_:)
関数のクロージャ式バージョンを示しています。
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
Note that the declaration of parameters and return type for this inline closure is identical to the declaration from the backward(_:_:)
function. In both cases, it’s written as (s1: String, s2: String) -> Bool
. However, for the inline closure expression, the parameters and return type are written inside the curly braces, not outside of them.
このインライン クロージャのパラメータと戻り値の型の宣言は、backward(_:_:)
関数の宣言と同じであることに注意してください。 どちらの場合も、(s1: String, s2: String) -> Bool
として記述されます。 ただし、インライン クロージャ式の場合、パラメータと戻り値の型は中括弧の外側ではなく、内側に記述されます。
The start of the closure’s body is introduced by the in
keyword. This keyword indicates that the definition of the closure’s parameters and return type has finished, and the body of the closure is about to begin.
クロージャの本体の始まりは、in
キーワードによって導入されます。 このキーワードは、クロージャのパラメータと戻り値の型の定義が終了し、クロージャの本体が始まろうとしていることを示します。
Because the body of the closure is so short, it can even be written on a single line:
クロージャの本体は非常に短いため、単一行で記述することもできます。
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
This illustrates that the overall call to the sorted(by:)
method has remained the same. A pair of parentheses still wrap the entire argument for the method. However, that argument is now an inline closure.
これは、sorted(by:)
メソッドの呼び出し全体が同じままであることを示しています。 かっこのペアは、まだメソッドの引数全体を囲んでいます。 ただし、その引数はいまはインライン クロージャです。
Inferring Type From Context
コンテキストからの型の推測
Because the sorting closure is passed as an argument to a method, Swift can infer the types of its parameters and the type of the value it returns. The sorted(by:)
method is being called on an array of strings, so its argument must be a function of type (String, String) -> Bool
. This means that the (String, String)
and Bool
types don’t need to be written as part of the closure expression’s definition. Because all of the types can be inferred, the return arrow (->
) and the parentheses around the names of the parameters can also be omitted:
ソート クロージャは引数としてメソッドに渡されるため、Swift はそのパラメータの型と返される値の型を推測できます。 sorted(by:)
メソッドは文字列の配列に対して呼び出されるため、その引数は (String, String) -> Bool
型の関数である必要があります。 これは、(String, String)
型と Bool
型をクロージャ式の定義の一部として記述する必要がないことを意味します。 すべての型を推論できるため、戻り矢印 (->
) とパラメータ名の周囲のかっこも省略できます。
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
It’s always possible to infer the parameter types and return type when passing a closure to a function or method as an inline closure expression. As a result, you never need to write an inline closure in its fullest form when the closure is used as a function or method argument.
クロージャをインライン クロージャ式として関数またはメソッドに渡すときは、パラメータの型と戻り値の型を推測することが常に可能です。 その結果、クロージャが関数またはメソッドの引数として使用される場合、インライン クロージャを完全な形式で記述する必要はありません。
Nonetheless, you can still make the types explicit if you wish, and doing so is encouraged if it avoids ambiguity for readers of your code. In the case of the sorted(by:)
method, the purpose of the closure is clear from the fact that sorting is taking place, and it’s safe for a reader to assume that the closure is likely to be working with String
values, because it’s assisting with the sorting of an array of strings.
ただし、必要に応じて型を明示的にすることもできます。コードの読者にとって曖昧さが避けられるのであれば、そうすることをお勧めします。 sorted(by:)
メソッドの場合、ソートが行われているという事実からクロージャの目的は明らかであり、クロージャは String
値を処理する可能性が高いと読者が想定しても安全です。なぜなら文字列の配列のソートをしているからです。
Implicit Returns from Single-Expression Closures
単一式クロージャからの暗黙的な戻り
Single-expression closures can implicitly return the result of their single expression by omitting the return
keyword from their declaration, as in this version of the previous example:
単一式クロージャは、前の例のこのバージョンのように、宣言から return
キーワードを省略することで、単一式の結果を暗黙的に返すことができます。
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
Here, the function type of the sorted(by:)
method’s argument makes it clear that a Bool
value must be returned by the closure. Because the closure’s body contains a single expression (s1 > s2
) that returns a Bool
value, there’s no ambiguity, and the return
keyword can be omitted.
ここで、sorted(by:)
メソッドの引数の関数型は、クロージャによって Bool
値が返される必要があることが明確です。 クロージャの本体には Bool
値を返す単一の式 (s1 > s2
) が含まれているため、曖昧さはなく、return
キーワードは省略できます。
Shorthand Argument Names
短縮引数名
Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0
, $1
, $2
, and so on.
Swift は、インライン クロージャに短縮引数名を自動的に提供します。これを使用して、$0, $1, $2
などの名前でクロージャの引数の値を参照できます。
If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition. The type of the shorthand argument names is inferred from the expected function type, and the highest numbered shorthand argument you use determines the number of arguments that the closure takes. The in
keyword can also be omitted, because the closure expression is made up entirely of its body:
クロージャ式内でこれらの短縮引数名を使用すると、その定義からクロージャの引数リストを省略できます。 短縮引数名の型は、予期される関数の型から推測され、使用する最大番号の短縮引数によって、クロージャが受け取る引数の数が決まります。 クロージャー式はその本体だけで構成されているため、in
キーワードも省略できます。
reversedNames = names.sorted(by: { $0 > $1 } )
Here, $0
and $1
refer to the closure’s first and second String
arguments. Because $1
is the shorthand argument with highest number, the closure is understood to take two arguments. Because the sorted(by:)
function here expects a closure whose arguments are both strings, the shorthand arguments $0
and $1
are both of type String
.
ここで、$0
と $1
はクロージャの最初と 2 番目のString
引数を指します。 $1
は最大の数値を持つ短縮引数であるため、クロージャは 2 つの引数を取るものと理解されます。 ここのsorted(by:)
関数は引数が両方とも文字列であるクロージャを想定しているため、短縮引数$0
と$1
は両方ともString
型です。
Operator Methods
演算子のメソッド
There’s actually an even shorter way to write the closure expression above. Swift’s String
type defines its string-specific implementation of the greater-than operator (>
) as a method that has two parameters of type String
, and returns a value of type Bool
. This exactly matches the method type needed by the sorted(by:)
method. Therefore, you can simply pass in the greater-than operator, and Swift will infer that you want to use its string-specific implementation:
実際には、上記のクロージャ式を記述するさらに短い方法があります。 Swift の String
型は、大なり演算子 (>
) の文字列固有の実装を、String
型の 2 つのパラメータを持ち、Bool
型の値を返すメソッドとして定義します。 これは、sorted(by:)
メソッドで必要なメソッドのタイプと正確に一致します。 したがって、単に大なり演算子を渡すだけで、Swift はその文字列固有の実装を使用することを推測します。
reversedNames = names.sorted(by: >)
For more about operator methods, see Operator Methods.
演算子メソッドの詳細については、「演算子メソッド」を参照してください。
Trailing Closures
後続クロージャ
If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead. You write a trailing closure after the function call’s parentheses, even though the trailing closure is still an argument to the function. When you use the trailing closure syntax, you don’t write the argument label for the first closure as part of the function call. A function call can include multiple trailing closures; however, the first few examples below use a single trailing closure.
クロージャ式を関数の最後の引数として関数に渡す必要があり、クロージャ式が長い場合は、代わりに後続クロージャとして記述すると便利です。 後続クロージャが関数の引数であっても、関数呼び出しのかっこの後に後続クロージャを記述します。 後続クロージャ構文を使用する場合、関数呼び出しの一部として最初のクロージャの引数ラベルを記述しません。 関数呼び出しには複数の後続クロージャを含めることができます。 ただし、以下の最初のいくつかの例では、単一の後続クロージャを使用しています。
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
}
// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
// closure's body goes here
})
// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
The string-sorting closure from the Closure Expression Syntax section above can be written outside of the sorted(by:)
method’s parentheses as a trailing closure:
上記のクロージャ式の構文の文字列ソート クロージャは、sorted(by:)
メソッドのかっこの外側に後続クロージャとして記述することができます。
reversedNames = names.sorted() { $0 > $1 }
If a closure expression is provided as the function’s or method’s only argument and you provide that expression as a trailing closure, you don’t need to write a pair of parentheses ()
after the function or method’s name when you call the function:
クロージャ式が関数またはメソッドの唯一の引数として指定され、その式を末尾のクロージャとして指定する場合、関数を呼び出すときに関数またはメソッドの名前の後にかっこ ()
のペアを記述する必要はありません。
reversedNames = names.sorted { $0 > $1 }
Trailing closures are most useful when the closure is sufficiently long that it isn’t possible to write it inline on a single line. As an example, Swift’s Array
type has a map(_:)
method, which takes a closure expression as its single argument. The closure is called once for each item in the array, and returns an alternative mapped value (possibly of some other type) for that item. You specify the nature of the mapping and the type of the returned value by writing code in the closure that you pass to map(_:)
.
後続クロージャは、クロージャが十分に長く、単一行でインラインで記述することができない場合に最も役立ちます。 一例として、Swift の Array
タイプには、クロージャ式を 1 つの引数として受け取る
メソッドがあります。 クロージャは配列内の項目ごとに 1 回呼び出され、その項目の代替マップ値 (おそらく他の型) を返します。 マッピングの性質と戻り値の型を指定するには、map(_:)
map(_:)
に渡すクロージャ内にコードを記述します。
After applying the provided closure to each array element, the map(_:)
method returns a new array containing all of the new mapped values, in the same order as their corresponding values in the original array.
提供されたクロージャを各配列要素に適用した後、map(_:)
メソッドは、新しいマップされた値をすべて含む新しい配列を、元の配列の対応する値と同じ順序で返します。
Here’s how you can use the map(_:)
method with a trailing closure to convert an array of Int
values into an array of String
values. The array [16, 58, 510]
is used to create the new array ["OneSix", "FiveEight", "FiveOneZero"]
:
ここでは、map(_:)
メソッドを末尾クロージャとともに使用して、Int
値の配列を String
値の配列に変換する方法を示します。 配列 [16, 58, 510]
は、新しい配列 ["OneSix", "FiveEight", "FiveOneZero"]
を作成するために使用されます。
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
The code above creates a dictionary of mappings between the integer digits and English-language versions of their names. It also defines an array of integers, ready to be converted into strings.
上記のコードは、整数の数字とその名前の英語版との間のマッピングの辞書を作成します。 また、文字列に変換できる整数の配列も定義します。
You can now use the numbers
array to create an array of String
values, by passing a closure expression to the array’s map(_:)
method as a trailing closure:
これで、numbers
配列を使用して String
値の配列を作成できるようになりました。これには、クロージャ式を配列の map(_:)
メソッドに後続クロージャとして渡します。
let strings = numbers.map { (number) -> String in
var number = number
var output = ""
repeat {
output = digitNames[number % 10]! + output
number /= 10
} while number > 0
return output
}
// strings is inferred to be of type [String]
// its value is ["OneSix", "FiveEight", "FiveOneZero"]
The map(_:)
method calls the closure expression once for each item in the array. You don’t need to specify the type of the closure’s input parameter, number
, because the type can be inferred from the values in the array to be mapped.
map(_:)
メソッドは、配列内の項目ごとにクロージャ式を 1 回呼び出します。 クロージャの入力パラメータの型であるnumber
を指定する必要はありません。型はマッピングされる配列の値から推測できるためです。
In this example, the variable number
is initialized with the value of the closure’s number
parameter, so that the value can be modified within the closure body. (The parameters to functions and closures are always constants.) The closure expression also specifies a return type of String
, to indicate the type that will be stored in the mapped output array.
この例では、変数number
はクロージャのnumber
パラメータの値で初期化されるため、クロージャ本体内で値を変更できます。 (関数とクロージャへのパラメータは常に定数です。)クロージャ式では、マップされた出力配列に格納される型を示すために、戻り値の型である String
も指定します。
The closure expression builds a string called output
each time it’s called. It calculates the last digit of number
by using the remainder operator (number % 10
), and uses this digit to look up an appropriate string in the digitNames
dictionary. The closure can be used to create a string representation of any integer greater than zero.
クロージャー式は呼び出されるたびに、output
という文字列を構築します。 剰余演算子 (number
% 10) を使用してnumber
の最後の桁を計算し、この数値を使用して digitNames
dictionary 内の適切な文字列を検索します。 クロージャを使用すると、ゼロより大きい任意の整数の文字列表現を作成できます。
Note
注釈
The call to the digitNames
dictionary’s subscript is followed by an exclamation point (!
), because dictionary subscripts return an optional value to indicate that the dictionary lookup can fail if the key doesn’t exist. In the example above, it’s guaranteed that number % 10
will always be a valid subscript key for the digitNames
dictionary, and so an exclamation point is used to force-unwrap the String
value stored in the subscript’s optional return value.
digitNames
辞書の添字の呼び出しの後には感嘆符 (!
) が続きます。これは、辞書の添字が、キーが存在しない場合に辞書検索が失敗する可能性があることを示すオプショナル値を返すためです。 上の例では、number % 10
が常に digitNames
dictionary の有効な添え字キーであることが保証されているため、添え字のオプショナル戻り値に格納されているString
値を強制的にアンラップするために感嘆符が使用されています。
The string retrieved from the digitNames
dictionary is added to the front of output
, effectively building a string version of the number in reverse. (The expression number % 10
gives a value of 6
for 16
, 8
for 58
, and 0
for 510
.)
digitNames
辞書から取得した文字列はoutput
の前に追加され、事実上、数値の文字列バージョンを逆に構築します。 (式「number % 10
」は、16
の場合は 6
、58
の場合は 8
、510
の場合は 0
の値を与えます。)
The number
variable is then divided by 10
. Because it’s an integer, it’s rounded down during the division, so 16
becomes 1
, 58
becomes 5
, and 510
becomes 51
.
次に、number
変数は 10
で除算されます。これは整数であるため、除算中に切り捨てられるため、16
は 1
になり、58
は 5
になり、510
は 51
になります。
The process is repeated until number
is equal to 0
, at which point the output
string is returned by the closure, and is added to the output array by the map(_:)
method.
このプロセスは、number
が 0
に等しくなるまで繰り返され、その時点でoutput
文字列がクロージャによって返され、map(_:)
メソッドによって出力配列に追加されます。
The use of trailing closure syntax in the example above neatly encapsulates the closure’s functionality immediately after the function that closure supports, without needing to wrap the entire closure within the map(_:)
method’s outer parentheses.
上記の例で後続クロージャ構文を使用すると、クロージャ全体をmap(_:)
メソッドの外側の括弧で囲む必要がなく、クロージャがサポートする関数の直後にクロージャの機能がきちんとカプセル化されます。
If a function takes multiple closures, you omit the argument label for the first trailing closure and you label the remaining trailing closures. For example, the function below loads a picture for a photo gallery:
関数が複数のクロージャを取る場合は、最初の後続クロージャの引数ラベルを省略し、残りの後続クロージャにラベルを付けます。 たとえば、以下の関数はフォト ギャラリーの画像を読み込みます。
func loadPicture(from server: Server, completion: (Picture) -> Void, onFailure: () -> Void) {
if let picture = download("photo.jpg", from: server) {
completion(picture)
} else {
onFailure()
}
}
When you call this function to load a picture, you provide two closures. The first closure is a completion handler that displays a picture after a successful download. The second closure is an error handler that displays an error to the user.
この関数を呼び出して画像をロードする場合、2 つのクロージャを提供します。 最初のクロージャーは、ダウンロードが成功した後に画像を表示する完了ハンドラーです。 2 番目のクロージャは、ユーザーにエラーを表示するエラー ハンドラーです。
loadPicture(from: someServer) { picture in
someView.currentPicture = picture
} onFailure: {
print("Couldn't download the next picture.")
}
In this example, the loadPicture(from:completion:onFailure:)
function dispatches its network task into the background, and calls one of the two completion handlers when the network task finishes. Writing the function this way lets you cleanly separate the code that’s responsible for handling a network failure from the code that updates the user interface after a successful download, instead of using just one closure that handles both circumstances.
この例では、loadPicture(from:completion:onFailure:)
関数はネットワーク タスクをバックグラウンドにディスパッチし、ネットワーク タスクが終了すると 2 つの完了ハンドラーのいずれかを呼び出します。 この方法で関数を作成すると、両方の状況を処理する 1 つのクロージャを使用するのではなく、ネットワーク障害の処理を担当するコードと、ダウンロードの成功後にユーザー インターフェイスを更新するコードを明確に分離できます。
Note
注釈
Completion handlers can become hard to read, especially when you have to nest multiple handlers. An alternate approach is to use asynchronous code, as described in Concurrency.
完了ハンドラーは、特に複数のハンドラーをネストする必要がある場合、読みにくくなることがあります。 別のアプローチは、同時実行性で説明されているように、非同期コードを使用することです。
Capturing Values
値の取得
A closure can capture constants and variables from the surrounding context in which it’s defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.
クロージャは、クロージャが定義されている領域の属性から定数と変数をキャプチャ(取得)できます。 クロージャは、定数や変数を定義した元のスコープが存在しない場合でも、その本体内からそれらの定数や変数の値を参照したり変更したりできます。
In Swift, the simplest form of a closure that can capture values is a nested function, written within the body of another function. A nested function can capture any of its outer function’s arguments and can also capture any constants and variables defined within the outer function.
Swift では、値を取得できるクロージャの最も単純な形式は、別の関数内に記述されたネストされた関数です。 ネストされた関数は、その外側の関数の引数をキャプチャでき、外側の関数内で定義された定数や変数もキャプチャできます。
Here’s an example of a function called makeIncrementer
, which contains a nested function called incrementer
. The nested incrementer()
function captures two values, runningTotal
and amount
, from its surrounding context. After capturing these values, incrementer
is returned by makeIncrementer
as a closure that increments runningTotal
by amount
each time it’s called.
これは makeIncrementer
という関数の例です。これには、incrementer
というネストされた関数が含まれています。 ネストされた incrementer()
関数は、領域の属性から 2 つの値、runningTotal
と amount
を取得します。 これらの値を取得した後、makeIncrementer
によって incrementer
が呼び出されるたびに runningTotal
by amount
をインクリメントするクロージャとして返されます。
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
The return type of makeIncrementer
is () -> Int
. This means that it returns a function, rather than a simple value. The function it returns has no parameters, and returns an Int
value each time it’s called. To learn how functions can return other functions, see Function Types as Return Types.
makeIncrementer
の戻り値の型は () -> Int
です。 これは、単純な値ではなく関数を返すことを意味します。 返される関数にはパラメータがなく、呼び出されるたびに Int
値を返します。 関数が他の関数を返す方法については、「戻り値の型としての関数の型」を参照してください。
The makeIncrementer(forIncrement:)
function defines an integer variable called runningTotal
, to store the current running total of the incrementer that will be returned. This variable is initialized with a value of 0
.
makeIncrementer(forIncrement:)
関数は、runningTotal
と呼ばれる整変数を定義し、返されるインクリメンタの現在の累計を保存します。 この変数は値 0
で初期化されます。
The makeIncrementer(forIncrement:)
function has a single Int
parameter with an argument label of forIncrement
, and a parameter name of amount
. The argument value passed to this parameter specifies how much runningTotal
should be incremented by each time the returned incrementer function is called. The makeIncrementer
function defines a nested function called incrementer
, which performs the actual incrementing. This function simply adds amount
to runningTotal
, and returns the result.
makeIncrementer(forIncrement:)
関数には、引数ラベル forIncrement
とパラメータ名 amount
を持つ単一の Int
パラメータがあります。 このパラメータに渡される引数値は、返されたインクリメンタ関数が呼び出されるたびに、runningTotal
をどれだけ増分するかを指定します。 makeIncrementer
関数は、実際のインクリメントを実行する incrementer
と呼ばれるネストされた関数を定義します。 この関数は、runningTotal
に金額を加算し、結果を返します。
When considered in isolation, the nested incrementer()
function might seem unusual:
単独で考えると、ネストされた incrementer()
関数は妙に見えるかもしれません。
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
The incrementer()
function doesn’t have any parameters, and yet it refers to runningTotal
and amount
from within its function body. It does this by capturing a reference to runningTotal
and amount
from the surrounding function and using them within its own function body. Capturing by reference ensures that runningTotal
and amount
don’t disappear when the call to makeIncrementer
ends, and also ensures that runningTotal
is available the next time the incrementer
function is called.
incrementer()
関数にはパラメータがありませんが、関数本体内からrunningTotal
とamount
を参照します。 これは、外側の関数からrunningTotal
とamount
への参照を取得し、それらを独自の関数本体内で使用することによって行われます。 参照によるキャプチャにより、makeIncrementer
の呼び出しが終了したときにrunningTotal
とamount
が消えず、次回incrementer
関数が呼び出されたときにrunningTotal
が確実に使用できるようになります。
Note
注釈
As an optimization, Swift may instead capture and store a copy of a value if that value isn’t mutated by a closure, and if the value isn’t mutated after the closure is created.
最適化として、値がクロージャによって変更されていない場合、およびクロージャの作成後に値が変更されていない場合、Swift は代わりに値のコピーをキャプチャして保存することがあります。
Swift also handles all memory management involved in disposing of variables when they’re no longer needed.
Swift は、不要になった変数の破棄に伴うすべてのメモリ管理も処理します。
Here’s an example of makeIncrementer
in action:
makeIncrementer の動作例を次に示します。
let incrementByTen = makeIncrementer(forIncrement: 10)
This example sets a constant called incrementByTen
to refer to an incrementer function that adds 10
to its runningTotal
variable each time it’s called. Calling the function multiple times shows this behavior in action:
この例では、incrementByTen
という定数を設定して、呼び出されるたびに runningTotal
変数に 10
を加算するインクリメンタ関数を参照します。 関数を複数回呼び出すと、実際の動作が示されます。
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30
If you create a second incrementer, it will have its own stored reference to a new, separate runningTotal
variable:
2 番目のインクリメンタを作成すると、新しい別の runningTotal
変数への独自の参照が保存されます。
let incrementBySeven = makeIncrementer(forIncrement: 7)
incrementBySeven()
// returns a value of 7
Calling the original incrementer (incrementByTen
) again continues to increment its own runningTotal
variable, and doesn’t affect the variable captured by incrementBySeven
:
元のインクリメンタ (incrementByTen
) を再度呼び出すと、独自の runningTotal
変数が引き続きインクリメントされ、incrementBySeven
によってキャプチャされた変数には影響しません。
incrementByTen()
// returns a value of 40
Note
注釈
If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles. For more information, see Strong Reference Cycles for Closures.
クラス インスタンスのプロパティにクロージャを割り当て、クロージャがインスタンスまたはそのメンバーを参照することによってそのインスタンスをキャプチャする場合、クロージャとインスタンスの間に強力な参照サイクルが作成されます。 Swift はキャプチャ リストを使用して、これらの強力な参照サイクルを打ち破ります。 詳細については、「クロージャの強参照サイクル」を参照してください。
Closures Are Reference Types
クロージャは参照タイプです
In the example above, incrementBySeven
and incrementByTen
are constants, but the closures these constants refer to are still able to increment the runningTotal
variables that they have captured. This is because functions and closures are reference types.
上の例では、incrementBySeven
と incrementByTen
は定数ですが、これらの定数が参照するクロージャは、キャプチャした runningTotal
変数をインクリメントすることができます。 これは、関数とクロージャが参照型であるためです。
Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure. In the example above, it’s the choice of closure that incrementByTen
refers to that’s constant, and not the contents of the closure itself.
関数またはクロージャを定数または変数に代入するときは常に、実際にはその定数または変数を関数またはクロージャへの参照として設定していることになります。 上の例では、incrementByTen
が参照する定数はクロージャの選択であり、クロージャ自体の内容ではありません。
This also means that if you assign a closure to two different constants or variables, both of those constants or variables refer to the same closure.
これは、クロージャを 2 つの異なる定数または変数に代入すると、それらの定数または変数の両方が同じクロージャを参照することも意味します。
let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// returns a value of 50
incrementByTen()
// returns a value of 60
The example above shows that calling alsoIncrementByTen
is the same as calling incrementByTen
. Because both of them refer to the same closure, they both increment and return the same running total.
上の例は、alsoIncrementByTen
の呼び出しが incrementByTen
の呼び出しと同じであることを示しています。 どちらも同じクロージャを参照するため、どちらも増分して同じ累計を返します。
Escaping Closures
クロージャーのエスケープ
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write @escaping
before the parameter’s type to indicate that the closure is allowed to escape.
クロージャは、クロージャが引数として関数に渡されたときに関数をエスケープしますが、関数が戻った後に呼び出されます。 クロージャをパラメータの 1 つとして受け取る関数を宣言する場合、パラメータの型の前に @escaping
を記述して、クロージャがエスケープできることを示すことができます。
One way that a closure can escape is by being stored in a variable that’s defined outside the function. As an example, many functions that start an asynchronous operation take a closure argument as a completion handler. The function returns after it starts the operation, but the closure isn’t called until the operation is completed — the closure needs to escape, to be called later. For example:
クロージャがエスケープできる 1 つの方法は、関数の外部で定義された変数に格納されることです。 たとえば、非同期操作を開始する多くの関数は、完了ハンドラーとしてクロージャー引数を受け取ります。 関数はオペレーションの開始後に戻りますが、クロージャはオペレーションが完了するまで呼び出されません。後で呼び出されるように、クロージャはエスケープする必要があります。 例えば:
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
The someFunctionWithEscapingClosure(_:)
function takes a closure as its argument and adds it to an array that’s declared outside the function. If you didn’t mark the parameter of this function with @escaping
, you would get a compile-time error.
someFunctionWithEscapingClosure(_:)
関数は、クロージャを引数として受け取り、それを関数の外で宣言された配列に追加します。 この関数のパラメータを @escaping
でマークしなかった場合、コンパイル時エラーが発生します。
An escaping closure that refers to self
needs special consideration if self
refers to an instance of a class. Capturing self
in an escaping closure makes it easy to accidentally create a strong reference cycle. For information about reference cycles, see Automatic Reference Counting.
self
がクラスのインスタンスを参照している場合、self
を参照するエスケープ クロージャは特別な考慮が必要です。 エスケープクロージャでself
を捉えると、誤って強い参照サイクルを作成しやすくなります。 参照サイクルの詳細については、「自動参照カウント」を参照してください。
Normally, a closure captures variables implicitly by using them in the body of the closure, but in this case you need to be explicit. If you want to capture self
, write self
explicitly when you use it, or include self
in the closure’s capture list. Writing self
explicitly lets you express your intent, and reminds you to confirm that there isn’t a reference cycle. For example, in the code below, the closure passed to someFunctionWithEscapingClosure(_:)
refers to self
explicitly. In contrast, the closure passed to someFunctionWithNonescapingClosure(_:)
is a nonescaping closure, which means it can refer to self
implicitly.
通常、クロージャは変数をクロージャの本体内で使用することで暗黙的に変数をキャプチャしますが、この場合は明示的に行う必要があります。 self
をキャプチャしたい場合は、使用するときに self
を明示的に記述するか、クロージャのキャプチャ リストに self
を含めます。 self
を明示的に書くことで、自分の意図を表現することができ、参照サイクルがないことを確認するように促します。 たとえば、以下のコードでは、someFunctionWithEscapingClosure(:)
に渡されるクロージャは、明示的にself
参照します。 対照的に、someFunctionWithNonescapingClosure(:)
に渡されるクロージャは非エスケープ クロージャであり、暗黙的にself
を参照できることを意味します。
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
}
class SomeClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure { self.x = 100 }
someFunctionWithNonescapingClosure { x = 200 }
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x)
// Prints "200"
completionHandlers.first?()
print(instance.x)
// Prints "100"
Here’s a version of doSomething()
that captures self
by including it in the closure’s capture list, and then refers to self
implicitly:
以下は、クロージャのキャプチャ リストに含めることで self
をキャプチャし、暗黙的に self
を参照する doSomething()
のバージョンです。
class SomeOtherClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure { [self] in x = 100 }
someFunctionWithNonescapingClosure { x = 200 }
}
}
If self
is an instance of a structure or an enumeration, you can always refer to self
implicitly. However, an escaping closure can’t capture a mutable reference to self
when self
is an instance of a structure or an enumeration. Structures and enumerations don’t allow shared mutability, as discussed in Structures and Enumerations Are Value Types.
self
が構造体または列挙体のインスタンスである場合、いつでも暗黙的に self
を参照できます。 ただし、self
が構造体または列挙型のインスタンスである場合、エスケープ クロージャは self
への可変参照をキャプチャできません。 「構造体と列挙型は値の型である」で説明されているように、構造体と列挙型では共有可変性が許可されません。
struct SomeStruct {
var x = 10
mutating func doSomething() {
someFunctionWithNonescapingClosure { x = 200 } // Ok
someFunctionWithEscapingClosure { x = 100 } // Error
}
}
The call to the someFunctionWithEscapingClosure
function in the example above is an error because it’s inside a mutating method, so self
is mutable. That violates the rule that escaping closures can’t capture a mutable reference to self
for structures.
上の例の someFunctionWithEscapingClosure
関数の呼び出しは、変更メソッド内にあるためエラーとなり、self
は変更可能です。 これは、クロージャをエスケープすると構造体の self
への変更可能な参照をキャプチャできないというルールに違反します。
Autoclosures
オートクロージャ
An autoclosure is a closure that’s automatically created to wrap an expression that’s being passed as an argument to a function. It doesn’t take any arguments, and when it’s called, it returns the value of the expression that’s wrapped inside of it. This syntactic convenience lets you omit braces around a function’s parameter by writing a normal expression instead of an explicit closure.
オートクロージャは、関数に引数として渡される式をラップするために自動的に作成されるクロージャです。 引数は取らず、呼び出されると、内部にラップされている式の値を返します。 この構文上の利便性により、明示的なクロージャの代わりに通常の式を記述することで、関数のパラメータを囲む中括弧を省略できます。
It’s common to call functions that take autoclosures, but it’s not common to implement that kind of function. For example, the assert(condition:message:file:line:)
function takes an autoclosure for its condition
and message
parameters; its condition
parameter is evaluated only in debug builds and its message
parameter is evaluated only if condition
is false
.
自動クロージャを受け取る関数を呼び出すのは一般的ですが、そのような関数を実装するのは一般的ではありません。 たとえば、assert(condition:message:file:line:)
関数は、condition
パラメータとmessage
パラメータの自動クロージャを受け取ります。 そのcondition
パラメータはデバッグ ビルドでのみ評価され、そのmessage
パラメータはcondition
が false
の場合にのみ評価されます。
An autoclosure lets you delay evaluation, because the code inside isn’t run until you call the closure. Delaying evaluation is useful for code that has side effects or is computationally expensive, because it lets you control when that code is evaluated. The code below shows how a closure delays evaluation.
オートクロージャを使用すると、クロージャを呼び出すまで内部のコードが実行されないため、評価を遅らせることができます。 評価の遅延は、コードをいつ評価するかを制御できるため、副作用があるコードや計算コストが高いコードに役立ちます。 以下のコードは、クロージャがどのように評価を遅らせるかを示しています。
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// Prints "5"
let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
// Prints "5"
print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"
print(customersInLine.count)
// Prints "4"
Even though the first element of the customersInLine
array is removed by the code inside the closure, the array element isn’t removed until the closure is actually called. If the closure is never called, the expression inside the closure is never evaluated, which means the array element is never removed. Note that the type of customerProvider
isn’t String
but () -> String
— a function with no parameters that returns a string.
CustomersInLine
配列の最初の要素はクロージャ内のコードによって削除されますが、配列要素はクロージャが実際に呼び出されるまで削除されません。 クロージャが呼び出されない場合、クロージャ内の式は決して評価されません。つまり、配列要素は決して削除されません。 customerProvider
のタイプは String
ではなく、() -> String
(文字列を返すパラメータのない関数) であることに注意してください。
You get the same behavior of delayed evaluation when you pass a closure as an argument to a function.
クロージャを引数として関数に渡すと、遅延評価と同じ動作が得られます。
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } )
// Prints "Now serving Alex!"
The serve(customer:)
function in the listing above takes an explicit closure that returns a customer’s name. The version of serve(customer:)
below performs the same operation but, instead of taking an explicit closure, it takes an autoclosure by marking its parameter’s type with the @autoclosure
attribute. Now you can call the function as if it took a String
argument instead of a closure. The argument is automatically converted to a closure, because the customerProvider
parameter’s type is marked with the @autoclosure
attribute.
上記のリストのserve(customer:)
関数は、顧客の名前を返す明示的なクロージャを受け取ります。 以下のバージョンのserve(customer:)
は同じ操作を実行しますが、明示的なクロージャを取得する代わりに、パラメータの型を @autoclosure
属性でマークすることで自動クロージャを取得します。 これで、クロージャではなくString
引数を取ったかのように関数を呼び出すことができます。 customerProvider
パラメータの型が @autoclosure
属性でマークされているため、引数は自動的にクロージャに変換されます。
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))
// Prints "Now serving Ewa!"
Note
注釈
Overusing autoclosures can make your code hard to understand. The context and function name should make it clear that evaluation is being deferred.
オートクロージャを使いすぎると、コードが理解しにくくなる可能性があります。 コンテキストと関数名により、評価が延期されていることを明確にする必要があります。
If you want an autoclosure that’s allowed to escape, use both the @autoclosure
and @escaping
attributes. The @escaping
attribute is described above in Escaping Closures.
エスケープを許可する自動クロージャが必要な場合は、@autoclosure
属性と @escaping
属性の両方を使用します。 @escaping
属性については、上記の「クロージャのエスケープ」で説明しています。
// customersInLine is ["Barry", "Daniella"]
var customerProviders: [() -> String] = []
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
customerProviders.append(customerProvider)
}
collectCustomerProviders(customersInLine.remove(at: 0))
collectCustomerProviders(customersInLine.remove(at: 0))
print("Collected \(customerProviders.count) closures.")
// Prints "Collected 2 closures."
for customerProvider in customerProviders {
print("Now serving \(customerProvider())!")
}
// Prints "Now serving Barry!"
// Prints "Now serving Daniella!"
In the code above, instead of calling the closure passed to it as its customerProvider
argument, the collectCustomerProviders(_:)
function appends the closure to the customerProviders
array. The array is declared outside the scope of the function, which means the closures in the array can be executed after the function returns. As a result, the value of the customerProvider
argument must be allowed to escape the function’s scope.
上記のコードでは、customerProvider
引数として渡されたクロージャを呼び出す代わりに、collectCustomerProviders(_:)
関数がクロージャを customerProviders
配列に追加します。 配列は関数のスコープ外で宣言されています。つまり、配列内のクロージャは関数が戻った後に実行できることを意味します。 その結果、customerProvider
引数の値が関数のスコープをエスケープできるようにする必要があります。