式(Expressions)
最終更新日: 2022/1/31 原文: https://docs.swift.org/swift-book/ReferenceManual/Expressions.html
Swift では、前置式、バイナリ式、基本式、後置式の 4 種類の式があります。式が評価されると、値を返すか、副作用を起こすか、またはその両方を引き起こします。
前置式とバイナリ式を使用すると、演算子をより小さな式に適用できます。基本式は概念的には最もシンプルな種類の式で、値にアクセスする方法を提供します。後置式は、前置式やバイナリ式と同様に、関数呼び出しやメンバアクセスなど、後置式を使用してより複雑な式を構築できます。各式は、下記のセクションで詳しく説明されています。
GRAMMAR OF AN EXPRESSION expression → try-operatoropt prefix-expression binary-expressionsopt expression-list → expression | expression , expression-list

前置式(Prefix Expressions)

前置式は、式と任意の前置演算子を組み合わせます。前置演算子は 1 つの引数を受け取り、その後に式が続きます。
これらの演算子の動作については、Basic Operators(基本演算子)Advanced Operators(高度な演算子)を参照ください。
Swift 標準ライブラリによって提供されている演算子については、Operator Declarations(演算子宣言)を参照ください。
GRAMMAR OF A PREFIX EXPRESSION prefix-expression → prefix-operatoropt postfix-expression prefix-expression → in-out-expression

In-Out 式(In-Out Expression)

in-out 式は、関数呼び出し式に in-out パラメータとして渡された変数にマークをします。
in-out式
in-out パラメータの詳細については、In-Out Parameters(In-Out パラメータ)を参照ください。
in-out 式は、Implicit Conversion to a Pointer Type(ポインタ型への暗黙変換)で説明されているように、ポインタが必要なコンテキストに非ポインタ引数を指定するときにも使用されます。
GRAMMAR OF AN IN-OUT EXPRESSION in-out-expression → & identifier

Try 演算子(Try Operator)

_Try 演算子_は、try 演算子の後にエラーをスローできる式が続く形で構成されます。形式は次のとおりです:
try演算子
try 式の値は expression の値です。
_オプショナル try 式_は try? 演算子の後にエラーをスローできる式が続く形で構成されます。形式は次のとおりです:
try?演算子
式がエラーをスローしない場合、try? の値は式の値を含むオプショナルです。それ以外の場合、try? の値は nil です。
_強制 try 式_は try! 演算子の後にエラーをスローできる式が続く形で構成されます。形式は次のとおりです:
try!演算子
try! の値は experssion の値です。式がエラーをスローすると、実行時エラーが発生します。
バイナリ演算子の左側の式に trytry? または try!、がマークされている場合、その演算子はバイナリ式全体に適用されます。一方で、括弧(())を使用して、演算子の適用範囲を明示することもできます。
1
//両方の関数呼び出しに適用されます
2
sum = try someThrowingFunction() + anotherThrowingFunction()
3
4
//両方の関数呼び出しに適用されます
5
sum = try (someThrowingFunction() + anotherThrowingFunction())
6
7
//エラー:最初の関数呼び出しにのみ適用されます
8
sum = (try someThrowingFunction()) + anotherThrowingFunction()
Copied!
バイナリ演算子が代入演算子の場合、または try 式が括弧で囲まれていない限り、try 式はバイナリ演算子の右側には使用できません。
tryawait 演算子の両方を含む場合は、最初に try が来なければなりません。
trytry?try! の使用方法についての詳細はError Handling(エラーハンドリング)を参照ください。
GRAMMAR OF A TRY EXPRESSION try-operator → try | try ? | try !

Await 演算子(Await Operator)

_await 式_は、await 演算子の後に非同期関数の結果を返す式が続けて構成されます。形式は次のとおりです:
await 演算子
await 式の値は experssion の値です。
await でマークされた式を_潜在的中断ポイント_と呼びます。非同期関数の実行は、await でマークされている箇所で中断することができます。また、同時並行コードの実行は他の点で中断されることはありません。つまり、潜在的中断ポイント間で、次の潜在的中断ポイントに行く前に状態の更新が完了する条件で、一時的に破壊された不変式を必要とする状態を、安全に更新することができます。
await 式は、async(priority:operation:) 関数に渡される末尾クロージャのように、非同期コンテキスト内でのみ使用することができます。defer 文、または同期関数型の自動クロージャでは使用できません。
バイナリ演算子の左側の式に await 演算子がマークされている場合、その演算子はバイナリ式全体に適用されます。ただし、括弧を使用して、演算子の適用範囲について明示することができます。
1
//両方の関数呼び出しに適用されます
2
sum = await someAsyncFunction() + anotherAsyncFunction()
3
4
//両方の関数呼び出しに適用されます
5
sum = await (someAsyncFunction() + anotherAsyncFunction())
6
7
//エラー:最初の関数呼び出しにのみ適用されます
8
sum = (await someAsyncFunction()) + anotherAsyncFunction()
Copied!
バイナリ演算子が代入演算子の場合、または await 式が括弧内に囲まれていない限り、await 式はバイナリ演算子の右側に使用できません。
式が awaittry 演算子の両方を含む場合、最初に try 演算子が来なければなりません。
GRAMMAR OF AN AWAIT EXPRESSION await-operatorawait

中置式(Infix Expressions)

_中置式_は、左右の引数を受け取る式と中置バイナリ演算子を組み合わせます。形式は次のとおりです:
バイナリ式
これらの演算子の動作については、Basic Operators(基本演算子)Advanced Operators(高度な演算子)を参照ください。
標準ライブラリによって提供されている演算子については、Operator Declarations(演算子宣言)を参照ください。
NOTE 構文解析時には、式はバイナリ演算子のフラットなリストを構成します。このリストは、演算子の優先順位を適用することによってツリーに変換されます。例えば、式 2 + 3 * 5 は、最初は5つの項目、2+3*、および 5 として解釈され、その後 (2 + (3 * 5)) のツリーに変換します
GRAMMAR OF A INFIX EXPRESSION infix-expression → infix-operator prefix-expression infix-expression → assignment-operatoropt prefix-expression infix-expression → conditional-operatoropt prefix-expression infix-expression → type-casting-operator infix-expressions → infix-expression infix-expressionsopt

代入演算子(Assignment Operator)

代入演算子は特定の式に新しい値を設定します。形式は次のとおりです:
代入演算子
value を評価した結果得られた値が expression に設定されます。式がタプルの場合、値は同じ数の要素を持つタプルでなければなりません。(タプルはネストすることもできます)。代入は、値の各部分から expression の中の対応する部分に対して行われます。例えば:
1
(a, _, (b, c)) = ("test", 9.45, (12, 3))
2
// a は"test"、 b は 12、 c は 3、 9.45 は無視されます
Copied!
代入演算子は任意の値を返しません。
GRAMMAR OF AN asSIGNMENT OPERATOR assignment-operator → =

三項条件演算子(Ternary Conditional Operator)

三項条件演算子は、条件の値に基づいて、2 つの値のうちの 1 つに評価されます。形式は次のとおりです:
三項条件演算子
条件が true と評価された場合、条件演算子は最初の式を評価し、その値を返します。それ以外の場合は、2 番目の式を評価してその値を返します。未使用の式は評価されません。
三項条件演算子を使用する例については、Ternary Conditional Operator(三項条件演算子)を参照ください。
GRAMMAR OF A CONDITIONAL OPERATOR conditional-operator → ? expression :
4 つの型キャスト演算子があります: is 演算子、as 演算子、as? 演算子、そして as! 演算子。
それらは次の形式を持っています:
型キャスト演算子
is 演算子は実行時に式が指定された型にキャストできるかどうかを確認します。キャストできる場合は true を返します。それ以外の場合は、false を返します。
as 演算子は、コンパイル時にキャストが常に成功するとわかっている場合にキャストを実行します。アップキャストは、中間変数を使用せずに型のスーパー型のインスタンスとして式を使用できます。下記のアプローチはどれも同等です。
1
func f(_ any: Any) { print("Function for Any") }
2
func f(_ int: Int) { print("Function for Int") }
3
let x = 10
4
f(x)
5
// Function for Int
6
7
let y: Any = x
8
f(y)
9
// Function for Any
10
11
f(x as Any)
12
// Function for Any
Copied!
ブリッジングを使用して、新しいインスタンスを作成せずに、String などの Swift 標準ライブラリ型の式を、それに相応する NSString などの Foudation 型で使用できるようにしています。ブリッジングの詳細については、Working with Foundation Typesを参照ください。
as? 演算子は、式の指定された_型_への条件付きキャストを実行します。as? 演算子は指定された_型_のオプショナルを返します。実行時に、キャストが成功した場合、_式_の値がオプショナルで返されます。それ以外の場合、返される値は nil です。指定された_型_へのキャストが失敗するか、成功することが明らかな場合は、コンパイルエラーが発生します。
as! 演算子は、指定された型に強制キャストを実行します。as! 演算子は、オプショナル型ではなく、指定された型の値を返します。キャストが失敗した場合は、実行時エラーが発生します。x as! T(x as? T)! の挙動と同じです。
型キャストの詳細や型キャスト演算子を使用する例については、Type Casting(型キャスト)を参照ください。
GRAMMAR OF A TYPE-CASTING OPERATOR type-casting-operator → is type type-casting-operator → as type type-casting-operator → as ? type type-casting-operator → as ! type

基本式(Primary Expressions)

基本式は最も基本的な種類の式です。それらは自身を式として使用したり、他のトークンと組み合わせたり、前置式、バイナリ式、および後置式を作成することができます。
GRAMMAR OF A PRIMARY EXPRESSION primary-expression → identifier generic-argument-clauseopt primary-expression → literal-expression primary-expression → self-expression primary-expression → superclass-expression primary-expression → closure-expression primary-expression → parenthesized-expression primary-expression → tuple-expression primary-expression → implicit-member-expression primary-expression → wildcard-expression primary-expression → key-path-expression primary-expression → selector-expression primary-expression → key-path-string-expression

リテラル式(Literal Expression)

リテラル式は、通常のリテラル(文字列や数など)、配列または辞書リテラル、playground リテラル、または下記の特別なリテラルのいずれかで構成されます。
Literal
Type
Value
#file
String
使用されているファイルへのパス
#fileID
String
使用されているファイルとモジュールの名前
#filePath
String
使用されているファイルへのパス
#line
Int
使用されている行番号
#column
Int
開始列番号
#function
String
使用されている宣言の名前
#dsohandle
UnsafeRawPointer
使用中の動的共有オブジェクト(DSO)ハンドル
#file の文字列値は、古い #filePath から新しい #fileID への移行を有効にするために、言語のバージョンによって異なります。現在、#file#filePath と同じ値を持ちます。将来の Swift のバージョンでは、#file は代わりに #fileID と同じ値を持ちます。将来のバージョンの挙動を適用するには、#file#fileID または #filePath に置き換える必要があります。
#fileID 式の文字列値はモジュール/ファイル形式です。ここで言う、「ファイル」は式が使用されているファイルの名前で、「モジュール」は、がこのファイルが属しているモジュールの名前です。#filePath 式の文字列値は、式が使用されているファイルへのフルパスです。Line Control Statement(行制御文)で説明されているように、これらの値はどちらも #sourceLocation に変わる可能性があります。#fileID#filePath とは異なり、ソースファイルへのフルパスをソースファイルに埋め込むことはできないため、より良いプライバシーを提供し、コンパイルされたバイナリのサイズを減させることができます。テスト、ビルドスクリプト、また配布されるプログラムの一部にはならないその他のコードの外側で #filePath を使用しないでください。
NOTE #fileID 式は、最初のスラッシュ(/)の前のテキストをモジュール名、最後のスラッシュ(/)の後のテキストをファイル名と読んでください。将来的には、MyModule/some/disambigation/myfile.swift などのように、複数のスラッシュが含まれている可能性があります。
#function の値は、関数内ではその関数の名前です。メソッド内では、そのメソッドの名前、プロパティ get または set 内ではプロパティ名、initsubscript のような特別なメンバ内では、そのキーワード名、およびファイルのトップレベルでは、現在のモジュール名です。
関数またはメソッドのパラメータのデフォルト値として使用すると、呼び出し側でデフォルト値の式が評価され、特別なリテラル値が決定します。
1
func logFunctionName(string: String = #function) {
2
print(string)
3
}
4
func myFunction() {
5
logFunctionName() // myFunction().
6
}
Copied!
_配列リテラル_は、順序付けられた値の集合です。形式は次のとおりです:
配列リテラル
配列内の最後の式の後にカンマ(,)を続けることもできます。配列リテラルの値は [T] 型で、T はその内部の式の型です。複数の型の式がある場合、T はそれらに最も近い共通のスーパー型になります。空の配列リテラルは、空の角括弧([])を使用し、指定された型の空の配列を作成するためにも使用できます。
1
var emptyArray: [Double] = []
Copied!
_辞書リテラル_は、順序のないキーバリューペアのコレクションです。形式は次のとおりです:
辞書リテラル
辞書内の最後の式の後にカンマ(,)を続けることができます。辞書リテラルの値は [Key:Value] 型で、Key はそのキー式の型、Value はその値式の型です。複数の型の式がある場合、キーとバリューはそれぞれの値に最も近い共通のスーパー型になります。空の辞書リテラルは、空の配列リテラルと区別するために、一対の括弧内にコロンを書きます([:])。空の辞書リテラルを使用して、指定されたキーとバリュー型の空の辞書リテラルを作成できます。
1
var emptyDictionary: [String: Double] = [:]
Copied!
_playground リテラル_は、プログラムエディタ内の色、ファイル、または画像の対話型な表現を作成するために Xcode によって使用されます。Xcode の外側のプレーンテキストの playground リテラルには、特別なリテラル構文を使用します。
Xcode の playground リテラルの使用方法については、Xcode ヘルプ内のAdd a color, file, or image literalを参照ください。
GRAMMAR OF A LITERAL EXPRESSION literal-expression → literal literal-expression → array-literal | dictionary-literal | playground-literal literal-expression → #file | #fileID | #filePath literal-expression → #line | #column | #function | #dsohandle array-literal → [ array-literal-itemsopt ] array-literal-items → array-literal-item ,opt | array-literal-item , array-literal-items array-literal-item → expression dictionary-literal → [ dictionary-literal-items ] | [ : ] dictionary-literal-items → dictionary-literal-item ,opt | dictionary-literal-item , dictionary-literal-items dictionary-literal-item → expression : expression playground-literal → #colorLiteral ( red : expression , green : expression , blue :expression , alpha : expression ) playground-literal → #fileLiteral ( resourceName : expression ) playground-literal → #imageLiteral ( resourceName : expression )

self 式(Self Expression)

self 式は、それが使用さえている現在の型またはインスタンスへの明示的な参照です。形式は次のとおりです:
Self式
イニシャライザ、subscript、またはインスタンスメソッドでは、self は、それが出現する現在の型のインスタンスを表します。型メソッドでは、self はそれが登場する現在の型を表します。
self 式は、関数パラメータなどスコープ内に同じ名前の別の変数があり、何を指すのかが曖昧な場合に、メンバへアクセスするときに指定します。例えば:
1
class SomeClass {
2
var greeting: String
3
init(greeting: String) {
4
self.greeting = greeting
5
}
6
}
Copied!
値型の mutating メソッドでは、その値型の新しいインスタンスを self に代入できます。例えば:
1
struct Point {
2
var x = 0.0, y = 0.0
3
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
4
self = Point(x: x + deltaX, y: y + deltaY)
5
}
6
}
Copied!
GRAMMAR OF A SELF EXPRESSION self-expression → self | self-method-expression | self-subscript-expression | self-initializer-expression self-method-expression → self . identifier self-subscript-expression → self [ function-call-argument-list ] self-initializer-expression → self . init

スーパークラス式(Superclass Expression)

_スーパークラス式_は、クラスがスーパークラスとやり取りすることを可能にします。次のいずれかの形式があります:
スーパークラス式
最初の形式はスーパークラスのメンバにアクセスするために使用されます。2 番目の形式は、スーパークラスの subscript の実装にアクセスするために使用されます。3 番目の形式は、スーパークラスのイニシャライザにアクセスするために使用されます。
サブクラスは、スーパークラスの実装を利用するために、メンバ、subscript、およびイニシャライザの実装でスーパークラス式を使用できます。
GRAMMAR OF A SUPERCLASS EXPRESSION superclass-expression → superclass-method-expression | superclass-subscript-expression | superclass-initializer-expression superclass-method-expression → super . identifier superclass-subscript-expression → super [ function-call-argument-list ] superclass-initializer-expression → super . init

クロージャ式(Closure Expression)

_クロージャ式_は、他のプログラミング言語では、_ラムダ_または_匿名関数_とも呼ばれているクロージャを作成します。関数宣言のように、クロージャには文が含まれており、その囲まれている範囲から定数と変数をキャプチャします。形式は次のとおりです:
クロージャ式
Function Declaration(関数宣言)で説明されているように、_parameters_は関数宣言内のパラメータと同じ形式です。
クロージャをより簡潔に書くことができるいくつかの特別な形式があります:
  • クロージャは、そのパラメータ、戻り値の型、またはその両方の型を省略できます。パラメータ名と型の両方を省略する場合は、文の前の in キーワードを省略してください。省略された型を推論できない場合は、コンパイルエラーが発生します
  • クロージャはそのパラメータ名を省略することができます。その際は暗黙的に $0$1$2 などのように $ の後ろにパラメータの位置を続けた名前が与えられます
  • 単一式からなるクロージャは、その式の値を返すことが明らかです。この式の内容は、囲まれている式の型を推論するときにも使用されます
次のクロージャ式は同等です:
1
myFunction { (x: Int, y: Int) -> Int in
2
return x + y
3
}
4
5
myFunction { x, y in
6
return x + y
7
}
8
9
myFunction { return $0 + $1 }
10
11
myFunction { $0 + $1 }
Copied!
関数の引数としてクロージャを渡す方法については、Function Call Expression(関数呼び出し式)を参照ください。
クロージャ式は、関数呼び出しの一部としてすぐにクロージャを使用するときなど、可変または定数に格納されることなく使用できます。上記のコードの myFunction に渡されたクロージャ式は、即時に使用される例です。その結果、クロージャ式がエスケープか非エスケープかは、式の周囲のコンテキストによって異なります。クロージャ式は、即時に呼ばれるか、非エスケープ関数の引数として渡されると、非エスケープです。それ以外の場合、クロージャ式はエスケープです。
クロージャのエスケープの詳細については、Escaping Closures(エスケープクロージャ)を参照ください。

キャプチャリスト(Capture Lists)

デフォルトでは、クロージャ式は、、周囲のスコープの定数と変数を強い参照を持ってキャプチャします。_キャプチャリスト_を使用して、クロージャ内で値をキャプチャする方法を明示的に制御できます。
キャプチャリストは、パラメータのリストの前に、角括弧([])で囲まれた式のカンマ(,)区切りのリストとして書かれます。キャプチャリストを使用する場合は、パラメータ名、パラメータ型、および戻り値の型を省略しても、in キーワードを使用する必要があります。
キャプチャリストへの各エントリは、クロージャが作成されたときに初期化されます。キャプチャリスト内の各エントリに対して、定数は周囲のスコープの同じ名前を持つ定数または変数の値で初期化できます。例えば、下記のコードでは、a はキャプチャリストに含まれていますが、b は含まれていません。
1
var a = 0
2
var b = 0
3
let closure = { [a] in
4
print(a, b)
5
}
6
7
a = 10
8
b = 10
9
closure()
10
11
// 0 10
Copied!
クロージャの範囲内の定数と周囲の範囲内の変数に a という同じ名前の異なる変数がありますが、b という名前の変数は 1 つだけです。内部スコープ内の a は、クロージャが作成されたときに外側の a 値で初期化されますが、それらの値は繋がっていません。つまり、これは、外側の範囲内の a の値の変化が内側の範囲内の a の値に影響を与えず、クロージャの内側の値の変化も外側の a に影響を与えません。対照的に、b という名前の変数は外側の範囲内に 1 つしかなく、クロージャの内側または外側からの変化は両方に影響を与えます。
キャプチャされた変数の型に参照セマンティクスがある場合、この区別はありません。例えば、下のコードに x という 2 つの変数がありますが、外部スコープの変数と内部スコープの定数は、両方とも参照セマンティクスのために同じオブジェクトを参照します。
1
class SimpleClass {
2
var value: Int = 0
3
}
4
var x = SimpleClass()
5
var y = SimpleClass()
6
let closure = { [x] in
7
print(x.value, y.value)
8
}
9
10
x.value = 10
11
y.value = 10
12
closure()
13
// 10 10
Copied!
式の値の型がクラスの場合は、式の値へ弱参照または非所有参照で取り込むために、キャプチャリスト内の式に weak または unowned をマークすることができます。
1
myFunction { print(self.title) } // 暗黙的な強参照
2
myFunction { [self] in print(self.title) } // 明示的な強参照
3
myFunction { [weak self] in print(self!.title) } // 弱参照
4
myFunction { [unowned self] in print(self.title) } // 非所有参照
Copied!
任意の式をキャプチャリスト内の名前付きの値にバインドすることもできます。クロージャが作成されたときに式が評価され、値は指定された強度でキャプチャされます。例えば:
1
// parent として self.parent を弱参照する
2
myFunction { [weak parent = self.parent] in print(parent!.title) }
Copied!
クロージャ式の詳細と例については、Closure Expressions(クロージャ式)を参照ください。キャプチャリストの詳細および例については、Resolving Strong Reference Cycles for Closures(クロージャの強参照循環の解消)を参照ください。
GRAMMAR OF A CLOSURE EXPRESSION closure-expression → { closure-signatureopt statementsopt } closure-signature → capture-listopt closure-parameter-clause throwsopt function-resultopt in closure-signature → capture-list in closure-parameter-clause → ( ) | ( closure-parameter-list ) | identifier-list closure-parameter-list → closure-parameter | closure-parameter , closure-parameter-list closure-parameter → closure-parameter-name type-annotationopt closure-parameter → closure-parameter-name type-annotation ... closure-parameter-name → identifier capture-list → [ capture-list-items ] capture-list-items → capture-list-item | capture-list-item , capture-list-items capture-list-item → capture-specifieropt identifier capture-list-item → capture-specifieropt identifier = expression capture-list-item → capture-specifieropt self-expression capture-specifier → weak | unowned | unowned(safe) | unowned(unsafe)

暗黙メンバ式(Implicit Member Expression)

_暗黙メンバ式_は、型推論によって暗黙的に型を決定できるコンテキストにおいて、列挙ケースや型メソッドなどの型のメンバにアクセスするための省略記法です。形式は次のとおりです:
暗黙メンバ式
例えば:
1
var x = MyEnumeration.someValue
2
x = .anotherValue
Copied!
推論された型がオプショナルの場合は、暗黙メンバ式にオプショナルでない型のメンバを使用することもできます。
1
var someOptional: MyEnumeration? = .someValue
Copied!
暗黙メンバ式の後にPostfix Expressions(後置式)でリストされている後置演算子またはその他の後置構文を続けることができます。これは_暗黙メンバ式チェーン_と呼ばれます。全ての後置式チェーンで同じ型を持つことが一般的ですが、最低限の要件として、暗黙メンバ式チェーン全体がそのコンテキストで暗黙的に推論される型と互換性がある必要があります。具体的には、暗黙的に推論される型がオプショナルの場合は、オプショナル以外の型の値を使用でき、クラス型の場合、そのサブクラスを使用できます。例えば:
1
class SomeClass {
2
static var shared = SomeClass()
3
static var sharedSubclass = SomeSubclass()
4
var a = AnotherClass()
5
}
6
class SomeSubclass: SomeClass { }
7
class AnotherClass {
8
static var s = SomeClass()
9
func f() -> SomeClass { return AnotherClass.s }
10
}
11
let x: SomeClass = .shared.a.f()
12
let y: SomeClass? = .shared
13
let z: SomeClass = .sharedSubclass
Copied!
上記のコードでは、x の型はそのコンテキストから暗黙的に推論された型と正確に一致し、y の型は Someclass から SomeClass? に変換され、z の型は SomeSubclass から SomeClass に変換されます。
GRAMMAR OF A IMPLICIT MEMBER EXPRESSION implicit-member-expression → . identifier

括弧で囲まれた式(Parenthesized Expression)

_括弧で囲まれた式_は、括弧で囲まれた式で構成されます。式を明示的にグループ化することで、括弧を使用して操作の優先順位を指定できます。括弧のグループ化は式の型を変更しません(例:(1) はただの Int です。
GRAMMAR OF A PARENTHESIZED EXPRESSION parenthesized-expression → ( expression )

タプル式(Tuple Expression)

タプル式は、括弧で囲まれた式のカンマ区切りのリストで構成されています。各式は、コロン(:)で区切られ、その前に識別子を指定することもできます。形式は次のとおりです:
タプル式
_タプル式_の各識別子は、タプル式の範囲内で一意な必要があります。ネストしたタプル式では、同じレベルでネスト識別子を一意にする必要があります。例えば、(a: 10, a: 20) はラベル a が同じレベルで 2 回使用されているため無効です。ただし、(a: 10, b: (a: 1, x: 2)) は有効です。a は 2 回使用されていますが、外側のタプルに 1 回、内側のタプルに 1 回使用されています。
タプル式には、式を全く含めなくても、2 つ以上の式を含めることもできます。括弧内の単一式は括弧で囲まれた式です。
NOTE 空のタプル式と空のタプル型はいずれもSwiftでは () で書きます。Void() のタイプエイリアスのため、空のタプル型を書くために使用できます。ただし、全てのタイプエイリアスと同様に、Void は常に型で、空のタプル式を書くためには使用できません。
GRAMMAR OF A TUPLE EXPRESSION tuple-expression → ( ) | ( tuple-element , tuple-element-list ) tuple-element-list → tuple-element | tuple-element , tuple-element-list tuple-element → expression | identifier : expression

ワイルドカード式(Wildcard Expression)

ワイルドカード式は、代入中に値を明示的に無視するために使用されます。例えば、次の代入式 10x に代入されますが、20 は無視されています:
1
(x, _) = (10, 20)
2
// x は 10 で 20 は 無視されます
Copied!
GRAMMAR OF A WILDCARD EXPRESSION wildcard-expression → _

Key-Path 式(Key-Path Expression)

_key-path 式_は、型のプロパティまたは subscript を参照します。key-value observing などのような、動的プログラミングのタスクで key-path 式を使用します。次の形式があります:
Key-Path 式
type name は、String[Int]、や Set<Int> などのジェネリックなパラメータを含めた、具体的な型の名前です。
path は、プロパティ名、subscript、オプショナルチェーン式、および強制アンラップ式で構成されます。これらの key-path コンポーネントのそれぞれは、必要に応じて任意の順序で繰り返すことができます。
コンパイル時には、key-path 式は KeyPathクラスのインスタンスに置き換えられます。
key-path を使用して値にアクセスするには、キーパスを subscript(keyPath:) に渡します。これは全ての型で利用可能です。例えば:
1
struct SomeStructure {
2
var someValue: Int
3
}
4
5
let s = SomeStructure(someValue: 12)
6
let pathToProperty = \SomeStructure.someValue
7
8
let value = s[keyPath: pathToProperty]
9
// value は 12
Copied!
type name は、型推論で暗黙的に型を決定できるコンテキストでは省略できます。次のコードは、\ someClass.someProperty の代わりに \.someProperty を使用しています:
1
class SomeClass: NSObject {
2
@objc dynamic var someProperty: Int
3
init(someProperty: Int) {
4
self.someProperty = someProperty
5
}
6
}
7
8
let c = SomeClass(someProperty: 10)
9
c.observe(\.someProperty) { object, change in
10
// ...
11
}
Copied!
path は、識別キーパス (\.self) を作成するために self を参照できます。識別キーパスは、インスタンス全体を参照しているので、それを使用して、変数に格納されている全てのデータを単一のステップでアクセスして変更できます。例えば:
1
var compoundValue = (a: 1, b: 2)
2
// compoundValue = (a: 10, b: 20) と同じ
3
compoundValue[keyPath: \.self] = (a: 10, b: 20)
Copied!
path には、プロパティのプロパティを参照するために、ピリオドで区切って複数のプロパティ名を含めることができます。このコードは、key-path 式 \OuterStructure.outer.someValue を使用して、OuterStructure 型の outer プロパティの someValue プロパティにアクセスしています:
1
struct OuterStructure {
2
var outer: SomeStructure
3
init(someValue: Int) {
4
self.outer = SomeStructure(someValue: someValue)
5
}
6
}
7
8
let nested = OuterStructure(someValue: 24)
9
let nestedKeyPath = \OuterStructure.outer.someValue
10
11
let nestedValue = nested[keyPath: nestedKeyPath]
12
// nestedValue は 24
Copied!
path は、subscript のパラメータ型が Hashable プロトコルに準拠している限り角括弧([])を使用して subscript を含めることができます。この例では、key-path の subscript を使用して、配列の 2 番目の要素にアクセスしています。
1
let greetings = ["hello", "hola", "bonjour", "안녕"]
2
let myGreeting = greetings[keyPath: \[String].[1]]
3
// myGreeting は 'hola'
Copied!
subscript で使用される値は、名前付きの値またはリテラルです。値は Value セマンティクスを使用してキーパス内にキャプチャされます。次のコードは、key-path 式と greetings 配列の 3 番目の要素の両方にアクセスするために、可変の index を使用しています。index が変更されると、key-path 式は依然として 3 番目の要素を参照する一方、クロージャは新しいインデックスを使用しています。
1
var index = 2
2
let path = \[String].[index]
3
let fn: ([String]) -> String = { strings in strings[index] }
4
5
print(greetings[keyPath: path])
6
// bonjour
7
print(fn(greetings))
8
// bonjour
9
10
// index に新しい値を設定しても、path には影響しません
11
index += 1
12
print(greetings[keyPath: path])
13
// bonjour
14
15
// fn が index を参照するので、新しい値を使用しています
16
print(fn(greetings))
17
// 안녕
Copied!
path はオプショナルチェーンと強制アンラップを使用できます。このコードは、オプショナルの文字列のプロパティにアクセスするためのキーパスでオプショナルチェーンを使用しています。
1
let firstGreeting: String? = greetings.first
2
print(firstGreeting?.count as Any)
3
// Optional(5)
4
5
// key-path を使用して同じことをしています
6
let count = greetings[keyPath: \[String].first?.count]
7
print(count as Any)
8
// Optional(5)
Copied!
キーパスのコンポーネントを、型内に深くネストされている値にアクセスために組み合わせることができます。次のコードは、これらのコンポーネントを組み合わせた key-path 式を使用して、配列内の辞書のプロパティの様々な値にアクセスしています:
1
let interestingNumbers = ["prime": [2, 3, 5, 7, 11, 13, 17],
2
"triangular": [1, 3, 6, 10, 15, 21, 28],
3
"hexagonal": [1, 6, 15, 28, 45, 66, 91]]
4
print(interestingNumbers[keyPath: \[String: [Int]].["prime"]] as Any)
5
// Optional([2, 3, 5, 7, 11, 13, 17])
6
print(interestingNumbers[keyPath: \[String: [Int]].["prime"]![0]])
7
// 2
8
print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count])
9
// 7
10
print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth])
11
// 64
Copied!
関数またはクロージャを使用できるコンテキストでは、key-path 式を使用できます。具体的には、(SomeType) -> Value 型の関数やクロージャの代わりに、基の型が SomeType で、そのパスが Value 型の値を生成することができます。
1
struct Task {
2
var description: String
3
var completed: Bool
4
}
5
var toDoList = [
6
Task(description: "Practice ping-pong.", completed: false),
7
Task(description: "Buy a pirate costume.", completed: true),
8
Task(description: "Visit Boston in the Fall.", completed: false),
9
]
10
11
// 以下の両方のアプローチは同等です
12
let descriptions = toDoList.filter(\.completed).map(\.description)
13
let descriptions2 = toDoList.filter { $0.completed }.map { $0.description }
Copied!
key-path 式の副作用は、式が評価される時点でのみ評価されます。例えば、key-path 式で subscript の内側の関数呼び出しを行うと、関数は、キーパスが使用される度にではなく、式を評価する際に 1 回だけ呼び出されます。
1
func makeIndex() -> Int {
2
print("Made an index")
3
return 0
4
}
5
// 下の行は makeIndex() を呼び出します
6
let taskKeyPath = \[Task][makeIndex()]
7
// Made an index
8
9
// taskKeyPath を使用すると makeIndex() は再び呼び出されません。
10
let someTask = toDoList[keyPath: taskKeyPath]
Copied!
Objective-C API とやり取りするコード内のキーパスの使用方法の詳細については、Using Objective-C Runtime Features in Swiftを参照ください。Key-Value Coding や Key-Value Observing については、Key-Value Coding Programming GuideKey-Value Observing Programming Guideを参照ください。
GRAMMAR OF A KEY-PATH EXPRESSION key-path-expression → \ typeopt . key-path-components key-path-components → key-path-component | key-path-component . key-path-components key-path-component → identifier key-path-postfixesopt | key-path-postfixes key-path-postfixes → key-path-postfix key-path-postfixesopt key-path-postfix → ? | ! | self | [ function-call-argument-list ]

Selector 式(Selector Expression)

セレクタ式を使用すると、Objective-C のメソッドまたはプロパティの get や set を参照するために使用されるセレクタにアクセスできます。形式は次のとおりです:
Selector 式
メソッド名とプロパティ名は、Objective-C ランタイムで使用可能なメソッドまたはプロパティを参照する必要があります。セレクタ式の値は Selector 型のインスタンスです。例えば:
1
class SomeClass: NSObject {
2
@objc let property: String
3
4
@objc(doSomethingWithInt:)
5
func doSomething(_ x: Int) { }
6
7
init(property: String) {
8
self.property = property
9
}
10
}
11
let selectorForMethod = #selector(SomeClass.doSomething(_:))
12
let selectorForPropertyGetter = #selector(getter: SomeClass.property)
Copied!
プロパティの get のセレクタを作成すると、プロパティ名は変数または定数プロパティを参照できます。対照的に、set のセレクタを作成すると、プロパティ名は変数プロパティのみ参照しなければなりません。
method name は、同じ名前でシグネチャが異なるメソッド間の曖昧さを軽減するために as 演算子と一緒にグループ化するための括弧を含めることができます。例えば:
1
extension SomeClass {
2
@objc(doSomethingWithString:)
3
func doSomething(_ x: String) { }
4
}
5
let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void)
Copied!
セレクタが実行時ではなくコンパイル時に作成されるため、コンパイラはメソッドまたはプロパティが存在すること、およびそれらが Objective-C ランタイムに公開されていることを確認できます。
NOTE メソッド名とプロパティ名は式ですが、それらは決して評価されません。
Objective-C API とやり取りする Swift コードでセレクタを使用する方法の詳細については、Using Objective-C Runtime Features in Swiftを参照ください。
GRAMMAR OF A SELECTOR EXPRESSION selector-expression → #selector ( expression ) selector-expression → #selector ( getter: expression ) selector-expression → #selector ( setter: expression )

Key-Path 文字列式(Key-Path String Expression)

key-path 文字列式を使用すると、Key-Value Coding や Key-Value Observing API で使用するために、Objective-C のプロパティを参照するための文字列にアクセスできます。形式は次のとおりです:
Key-Path文字列式
property name は、Objective-C ランタイムで使用可能なプロパティを参照する必要があります。コンパイル時には、key-path 文字列式は文字列リテラルに置き換えられます。例えば:
1
class SomeClass: NSObject {
2
@objc var someProperty: Int
3
init(someProperty: Int) {
4
self.someProperty = someProperty
5
}
6
}
7
8
let c = SomeClass(someProperty: 12)
9
let keyPath = #keyPath(SomeClass.someProperty)
10
11
if let value = c.value(forKey: keyPath) {
12
print(value)
13
}
14
// 12
Copied!
クラス内で key-path 文字列式を使用すると、クラス名なしでプロパティ名だけを書くことでそのクラスのプロパティを参照できます。
1
extension SomeClass {
2
func getSomeKeyPath() -> String {
3
return #keyPath(someProperty)
4
}
5
}
6
print(keyPath == c.getSomeKeyPath())
7
// true
Copied!
キーパス文字列は、実行時ではなくコンパイル時に作成されているため、コンパイラはプロパティが存在すること、およびそのプロパティが Objective-C ランタイムに公開されていることを確認できます。
Objective-C API とやり取りする Swift コードで key-path を使用する方法の詳細については、Using Objective-C Runtime Features in Swiftを参照ください。Key-Value Coding と Key-Value Observing については、Key-Value Coding Programming GuideKey-Value Observing Programming Guideを参照ください。
NOTE プロパティ名は式ですが、それらは決して評価されません。
GRAMMAR OF A KEY-PATH STRING EXPRESSION key-path-string-expression → #keyPath ( expression )

後置式(Postfix Expressions)

_後置式_は、後置演算子またはその他の後置構文を式に適用することによって形成されます。構文的には、全ての基本式も後置式です。
これらの演算子の動作については、Basic Operators(基本演算子)Advanced Operators(高度な演算子)を参照ください。
Swift 標準ライブラリによって提供されている演算子については、Operator Declarations(演算子宣言)を参照ください。
GRAMMAR OF A POSTFIX EXPRESSION postfix-expression → primary-expression postfix-expression → postfix-expression postfix-operator postfix-expression → function-call-expression postfix-expression → initializer-expression postfix-expression → explicit-member-expression postfix-expression → postfix-self-expression postfix-expression → subscript-expression postfix-expression → forced-value-expression postfix-expression → optional-chaining-expression

関数呼び出し式(Function Call Expression)

_関数呼び出し式_は、関数名とそれに続く関数の引数のカンマ区切りのリストからなる関数名で構成されています。関数呼び出し式は形式は次のとおりです:
関数呼び出し式1
function name は、関数型の任意の式です。
関数定義にパラメータ名が含まれている場合、関数呼び出しは、コロン(:)で区切られた引数値の前に名前を含める必要があります。この種の関数呼び出し式は形式は次のとおりです:
パラメータ名を含んだ関数呼び出し式
関数呼び出し式は、閉じ括弧(})の直後にクロージャ式の形で末尾クロージャを含めることができます。末尾クロージャは、最後の括弧内の引数の後の関数型の引数と解釈されます。最初のクロージャ式に引数ラベルは付けません。次のクロージャ式の前には引数ラベルを付けます。下記の例は、末尾クロージャの構文を使用して、 末尾クロージャを使用しない関数呼び出しバージョンと同等だということを示しています:
1
// someFunction 関数は引数として整数とクロージャを受け取ります
2
someFunction(x: x, f: { $0 == 13 })
3
someFunction(x: x) { $0 == 13 }
4
5
// anotherFunction 関数は引数として整数と 2 つのクロージャを受け取ります
6
anotherFunction(x: x, f: { $0 == 13 }, g: { print(99) })
7
anotherFunction(x: x) { $0 == 13 } g: { print(99) }
Copied!
末尾クロージャが関数の唯一の引数の場合は、括弧を省略できます。
1
// someMethod は唯一の引数としてクロージャを受け取ります
2
myData.someMethod() { $0 == 13 }
3
myData.someMethod { $0 == 13 }
Copied!
引数に末尾クロージャを含めるために、コンパイラは次のように左から右へ関数のパラメータを調べます:
末尾クロージャ
パラメータ
アクション
ラベルあり
ラベルあり
ラベルが同じ場合、クロージャはパラメータと一致します。それ以外の場合は、スキップされます
ラベルあり
ラベルなし
パラメータはスキップされます
ラベルなし
ラベルあり/なし
下記に定義されているように、パラメータが関数型と見なされる場合、クロージャはパラメータと一致します。それ以外の場合は、スキップされます。
末尾クロージャは、それが一致する関数のパラメータに渡されます。スキャンプロセス中にスキップされたパラメータには、値が渡されません。例えば、デフォルトのパラメータを使用できます。一致するパラメータを見つけた後、スキャンは次の末尾クロージャと次のパラメータに続きます。マッチングプロセスの最後に、全ての末尾クロージャが一致している必要があります。
構造上、パラメータが in-out パラメータではなく、次のいずれかの場合、パラメータは関数型と見なされます:
  • (Bool) -> Int のようにパラメータの型が関数型
  • @autoclosure () -> ((Bool) -> Int) のように、ラップされた式の型が関数型の自動クロージャパラメータ
  • ((Bool) -> Int)... のように、配列要素の型が関数型の可変長パラメータ
  • Optional<(Bool) -> Int> のように、型がオプショナルの 1 つ以上の層にラップされているパラメータ
  • (Optional<(Bool) -> Int>)... のように、上記の許可された型を組み合わせたパラメータ
末尾クロージャが機能的には関数型のように見えるが関数ではないパラメータと一致する場合、クロージャは必要に応じてラップされます。例えば、パラメータの型がオプショナルの型の場合、クロージャは自動的に Optional でラップされます
これは右から左にマッチングを実行していた Swift 5.3 以前のコードから移行を簡単にするために、スキャン方向で異なる結果を生成する場合は、古い右から左へ順序付けされ、コンパイラは警告を生成します。それ以降の Swift のバージョンでは常に左から右へ正しく順序付けします。
1
typealias Callback = (Int) -> Int
2
func someFunction(firstClosure: Callback? = nil,
3
secondClosure: Callback? = nil) {
4
let first = firstClosure?(10)
5
let second = secondClosure?(20)
6
print(first ?? "-", second ?? "-")
7
}
8
9
someFunction() // - -
10
someFunction { return $0 + 100 } // Ambiguous
11
someFunction { return $0 } secondClosure: { return $0 } // 10 20
Copied!
上記の例では、"Ambiguous"とマークされている関数の呼び出しは"- 120"が出力され、Swift 5.3 ではコンパイラが警告を生成します。それ以降の Swift のバージョンでは "110 -"が出力されます。
クラス、構造体、または列挙型は、Methods with Special Names(特別な名前のメソッド)で説明されているような、いくつかのメソッドの 1 つを宣言することで、関数呼び出しの糖衣構文(シンタックスシュガー)を使うことができます。

ポインタ型への暗黙変換(Implicit Conversion to a Pointer Type)

関数呼び出し式で、引数とパラメータが異なる場合、コンパイラは次のリストの暗黙的な変換の 1 つを適用することによって、その型が一致するようにします。
  • inout SomeType は、UnsafePointer<SomeType> または UnsafeMutablePointer<SomeType> になる可能性があります
  • inout Array<SomeType> は、UnsafePointer<SomeType> または UnsafeMutablePointer<SomeType> になる可能性があります
  • Array<SomeType> は、UnsafePointer<SomeType> になる可能性があります
  • StringUnsafePointer<CChar> になる可能性があります
次の 2 つの関数呼び出しは同等です:
1
func unsafeFunction(pointer: UnsafePointer<Int>) {
2
// ...
3
}
4
var myNumber = 1234
5
6
unsafeFunction(pointer: &myNumber)
7
withUnsafePointer(to: myNumber) { unsafeFunction(pointer: $0) }
Copied!
これらの暗黙の変換によって作成されたポインタは、関数呼び出しの間だけ有効です。未定義の動作を避けるために、関数呼び出しが終了した後までポインタを保持しないようにしてください。
NOTE 配列を暗黙的に安全でないポインタに変換すると、Swift は、配列のストレージが必要に応じて配列を変換またはコピーすることによって連続していることを保証します。例えば、この構文は、そのストレージに関する API の契約がない(動作が定義されているか定かではない) NSArray のサブクラスから Array にブリッジされた配列でこの構文を使用できます。配列のストレージがすでに連続していることを保証する必要がある場合、暗黙の変換を行わないようにするために、Array の代わりに ContigureArray を使用します
withUnsafePointer(to:) のような明示的な機能の代わりに、& を使うことで、低レベルの C 言語の関数を呼び出しやすくするのに役立ちます。ただし、他の Swift コードから関数を呼び出すときは、安全でない API を明示的に使用する代わりとして & を使用しないでください。
GRAMMAR OF A FUNCTION CALL EXPRESSION function-call-expression → postfix-expression function-call-argument-clause function-call-expression → postfix-expression function-call-argument-clauseopt