式(Expressions)
最終更新日: 2022/12/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
前置式は、式と任意の前置演算子を組み合わせます。前置演算子は 1 つの引数を受け取り、その後に式が続きます。
GRAMMAR OF A PREFIX EXPRESSION prefix-expression → prefix-operatoropt postfix-expression prefix-expression → in-out-expression
in-out 式は、関数呼び出し式に in-out パラメータとして渡された変数にマークをします。

in-out式
in-out 式は、Implicit Conversion to a Pointer Type(ポインタ型への暗黙変換)で説明されているように、ポインタが必要なコンテキストに非ポインタ引数を指定するときにも使用されます。
_Try 演算子_は、
try
演算子の後にエラーをスローできる式が続く形で構成されます。形式は次のとおりです:
try演算子
try
式の値は expression の値です。_オプショナル try 式_は
try?
演算子の後にエラーをスローできる式が続く形で構成されます。形式は次のとおりです:
try?演算子
式がエラーをスローしない場合、
try?
の値は式の値を含むオプショナルです。それ以外の場合、try?
の値は nil
です。_強制 try 式_は
try!
演算子の後にエラーをスローできる式が続く形で構成されます。形式は次のとおりです:
try!演算子
try!
の値は experssion の値です。式がエラーをスローすると、実行時エラーが発生します。バイナリ演算子の左側の式に
try
、try?
または try!
、がマークされている場合、その演算子はバイナリ式全体に適用されます。一方で、括弧(()
)を使用して、演算子の適用範囲を明示することもできます。//両方の関数呼び出しに適用されます
sum = try someThrowingFunction() + anotherThrowingFunction()
//両方の関数呼び出しに適用されます
sum = try (someThrowingFunction() + anotherThrowingFunction())
//エラー:最初の関数呼び出しにのみ適用されます
sum = (try someThrowingFunction()) + anotherThrowingFunction()
バイナリ演算子が代入演算子の場合、または
try
式が括弧で囲まれていない限り、try
式はバイナリ演算子の右側には使用できません。try
と await
演算子の両方を含む場合は、最初に try
が来なければなりません。GRAMMAR OF A TRY EXPRESSION try-operator →try
|try
?
|try
!
_await 式_は、
await
演算子の後に非同期関数の結果を返す式が続けて構成されます。形式は次のとおりです:
await 演算子
await
式の値は experssion の値です。await
でマークされた式を_潜在的中断ポイント_と呼びます。非同期関数の実行は、await
でマークされている箇所で中断することができます。また、同時並行コードの実行は他の点で中断されることはありません。つまり、潜在的中断ポイント間で、次の潜在的中断ポイントに行く前に状態の更新が完了する条件で、一時的に破壊された不変式を必要とする状態を、安全に更新することができます。await
式は、async(priority:operation:)
関数に渡される末尾クロージャのように、非同期コンテキスト内でのみ使用することができます。defer
文、または同期関数型の自動クロージャでは使用できません。バイナリ演算子の左側の式に
await
演算子がマークされている場合、その演算子はバイナリ式全体に適用されます。ただし、括弧を使用して、演算子の適用範囲について明示することができます。//両方の関数呼び出しに適用されます
sum = await someAsyncFunction() + anotherAsyncFunction()
//両方の関数呼び出しに適用されます
sum = await (someAsyncFunction() + anotherAsyncFunction())
//エラー:最初の関数呼び出しにのみ適用されます
sum = (await someAsyncFunction()) + anotherAsyncFunction()
バイナリ演算子が代入演算子の場合、また は
await
式が括弧内に囲まれていない限り、await
式はバイナリ演算子の右側に使用できません。式が
await
と try
演算子の両方を含む場合、最初に try
演算子が来なければなりません。GRAMMAR OF AN AWAIT EXPRESSION await-operator →await
_中置式_は、左右の引数を受け取る式と中置バイナリ演算子を組み合わせます。形式は次のとおりです:

バイナリ式
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
代入演算子は特定の式に新しい値を設定します。形式は次のとおりです:

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

三項条件演算子
条件が
true
と評価された場合、条件演算子は最初の式を評価し、その値を返します。それ以外の場合は、2 番目の式を評価してその値を返します。未使用の式は評価されません。4 つの型キャスト演算子があります:
is
演算子、as
演算子、as?
演算子、そして as!
演算子。それらは次の形式を持っています:

型キャスト演算子
is
演算子は実行時に式が指定された型にキャストできるかどうかを確認します。キャストできる場合は true
を返します。それ以外の場合は、false
を返します。as
演算子は、コンパイル時にキャストが常に成功するとわかっている場合にキャストを実行します。アップキャストは、中間変数を使用せずに型のスーパー型のインスタンスとして式を使用できます。下記のアプローチはどれも同等です。func f(_ any: Any) { print("Function for Any") }
func f(_ int: Int) { print("Function for Int") }
let x = 10
f(x)
// Function for Int
let y: Any = x
f(y)
// Function for Any
f(x as Any)
// Function for Any
ブリッジングを使用して、新しいインスタンスを作成せずに、
String
などの Swift 標準ライブラリ型の式を、それに相応する NSString
などの Foudation 型で使用できるようにしています。ブリッジングの詳細については、Working with Foundation Typesを参照ください。as?
演算子は、式の指定された_型_への条件付きキャストを実行します。as?
演算子は指定された_型_のオプショナルを返します。実行時に、キャストが成功した場合、_式_の値がオプショナルで返されます。それ以外の場合、返される値は nil
です。指定された_型_へのキャストが失敗するか、成功することが明らかな場合は、コンパイルエラーが発生します。as!
演算子は、指定された型に強制キャストを実行します。as!
演算子は、オプショナル型ではなく、指定された型の値を返します。キャストが失敗した場合は、実行時エラーが発生します。x as! T
は (x as? T)!
の挙動と同じです。基本式は最も基本的な種類の式です。それらは自身を式として使用したり、他のトークンと組み合わせたり、前置式、バイナリ式、および後置式を作成することができます。
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
リテラル式は、通常のリテラル(文字列や数など)、配列または辞書リテラル、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 内ではプロパティ名、init
や subscript
のような特別なメンバ内では、そのキーワード名、およびファイルのトップレベルでは、現在のモジュール名です。関数またはメソッドのパラメータのデフォルト値として使用すると、呼び出し側でデフォルト値の式が評価され、特別なリテラル値が決定します。
func logFunctionName(string: String = #function) {
print(string)
}
func myFunction() {
logFunctionName() // myFunction().
}
_配列リテラル_は、順序付けられた値の集合です。形式は次のとおりです:

配列リテラル
配列内の最後の式の後にカンマ(
,
)を続けることもできます。配列リテラルの値は [T]
型で、T
はその内部の式の型です。複数の型の式がある場合、T
はそれらに最も近い共通のスーパー型になります。空の配列リテラルは、空の角括弧([]
)を使用し、指定された型の空の配列を作成するためにも使用できます。var emptyArray: [Double] = []
_辞書リテラル_は、順序のないキーバリューペアのコレクションです。形式は次のとおりです:

辞書リテラル
辞書内の最後の式の後にカンマ(
,
)を続けることができます。辞書リテラルの値は [Key:Value]
型で、Key
はそのキー式の型、Value
はその値式の型です。複数の型の式がある場合、キーとバリューはそれぞれの値に最も近い共通のスーパー型になります。空の辞書リテラルは、空の配列リテラルと区別するため に、一対の括弧内にコロンを書きます([:]
)。空の辞書リテラルを使用して、指定されたキーとバリュー型の空の辞書リテラルを作成できます。var emptyDictionary: [String: Double] = [:]
_playground リテラル_は、プログラムエディタ内の色、ファイル、または画像の対話型な表現を作成するために Xcode によって使用されます。Xcode の外側のプレーンテキストの
playground
リテラルには、特別なリテラル構文を使用します。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式
イニシャライザ、サブスクリプト、またはインスタンスメソッドでは、
self
は、それが出現する現在の型のインスタンスを表します。型メソッドでは、self
はそれが登場する現在の型を表します。self
式は、関数パラメータなどスコープ内に同じ名前の別の変数があり、何を指すのかが曖昧な場合に、メンバへアクセスするときに指定します。例えば:class SomeClass {
var greeting: String
init(greeting: String) {
self.greeting = greeting
}
}
値型の mutating メソッドでは、その値型の新しいインスタンスを
self
に代入できます。例えば:struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
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
_スーパークラス式_は、クラスがスーパークラスとやり取りすることを可能にします。次のいずれかの形式があります:

スーパークラス式
最初の形式はスーパークラス のメンバにアクセスするために使用されます。2 番目の形式は、スーパークラスのサブスクリプトの実装にアクセスするために使用されます。3 番目の形式は、スーパークラスのイニシャライザにアクセスするために使用されます。
サブクラスは、スーパークラスの実装を利用するために、メンバ、サブスクリプト、およびイニシャライザの実装でスーパークラス式を使用できます。
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
_クロージャ式_は、他のプログラミング言語では、_ラムダ_または_匿名関数_とも呼ばれているクロージャを作成します。関数宣言のように、クロージャには文が含まれており、その囲まれている範囲から定数と変数をキャプチャします。形式は次のとおりです:

クロージャ式
クロージャ式で
throw
または async
を記述すると、クロージャはエラーをスローする、または非同期であることを明示します。
throwやawaitがマークしたクロージャ式
クロージャの本文に
try
式が含まれている場合、クロージャはエラーをスローすると見なします。同様に、await
式が含まれている場合は、非同期であると見なします。クロージャをより簡潔に書くことができるいくつかの特別な形式があります:
- クロージャは、そのパラメータ、戻り値の型、またはその両方の型を省略できます。パラメータ名と型の両方を省略する場合は、文の前の
in
キーワードを省略してください。省略された型を推論できない場合は、コンパイルエラーが発生します - クロージャはそのパラメータ名を省略することができます。その際は暗黙的に
$0
、$1
、$2
などのように$
の後ろにパラメータの位置を続けた名前が与えられます - 単一式からなるクロージャは、その式の値を返すことが明らかです。この式の内容は、囲まれている式の型を推論するときにも使用されます
次のクロージャ式は同等です:
myFunction { (x: Int, y: Int) -> Int in
return x + y
}
myFunction { x, y in
return x + y
}
myFunction { return $0 + $1 }
myFunction { $0 + $1 }
クロージャ式は、関数呼び出しの一部としてすぐにクロージャを使用するときなど、可変または定数に格納されることなく使用できます。上記のコードの
myFunction
に渡されたクロージャ式は、即時に使用される例です。その結果、クロージャ式がエスケープか非エスケープかは、式の周囲のコンテキストによって異なります。クロージャ式は、即時に呼ばれるか、非エスケープ関数の引数として渡されると、非エスケープです。それ以外の場合、クロージャ式はエスケープです。デフォルトでは、クロージャ式は、、周囲のスコープの定数と変数を強い参照を持ってキャプチャします。_キャプチャリスト_を使用して、クロージャ内で値をキャプチャする方法を明示的に制御できます。
キャプチャリストは、パラメータのリストの前に、角括弧(
[]
)で囲まれた式のカンマ(,
)区切りのリストとして書かれます。キャプチャリストを使用する場合は、パラメータ名、パラメータ型、および戻り値の型を省略しても、in
キーワードを使用する必要があります。キャプチャリストへの各エントリは、クロージャが作成されたときに初期化されます。キャプチャリスト内の各エントリに対して、定数は周囲のスコープの同じ名前を持つ定数または変数の値で初期化できます。例えば、下記のコードでは、
a
はキャプチャリストに含まれていますが、b
は含まれていません。var a = 0
var b = 0
let closure = { [a] in
print(a, b)
}
a = 10
b = 10
closure()
// 0 10
クロージャの範囲内の定数と周囲の範囲内の変数に
a
という同じ名前の異なる変数がありますが、b
という名前の変数は 1 つだけです。内部スコープ内の a
は、クロージャが作成されたときに外側の a
値で初期化されますが、それらの値は繋がっていません。つまり、これは、外側の範囲内の a
の値の変化が内側の範囲内の a
の値に影響を与えず、クロージャの内側の値の変化も外側の a
に影響を与えません。対照的に、b
という名前の変数は外側の範囲内に 1 つしかなく、クロージャの内側または外側からの変化は両方に影響を与えます。キャプチャされた変数の型に参照セマンティクスがある場合、この区別はありません。例えば、下のコードに
x
という 2 つの変数がありますが、外部スコープの変数と内部スコープの定数は、両方とも参照セマンティクスのために同じオブジェクトを参照します。class SimpleClass {
var value: Int = 0
}
var x = SimpleClass()
var y = SimpleClass()
let closure = { [x] in
print(x.value, y.value)
}
x.value = 10
y.value = 10
closure()
// 10 10
式の値の型がクラスの場合は、式の値へ弱参照または非所有参照で取り込むために、キャプチャリスト内の式に
weak
または unowned
をマークすることができます。myFunction { print(self.title) } // 暗黙的な強参照
myFunction { [self] in print(self.title) } // 明示的な強参照
myFunction { [weak self] in print(self!.title) } // 弱参照
myFunction { [unowned self] in print(self.title) } // 非所有参照
任意の式をキャプチャリスト内の名前付きの値にバインドすることもできます。クロージャが作成されたときに式が評価され、値は指定された強度でキャプチャされます。例えば:
// parent とし て self.parent を弱参照する
myFunction { [weak parent = self.parent] in print(parent!.title) }
クロージャ式の詳細と例については、Closure Expressions(クロージャ式)を参照ください。キャプチャリストの詳細および例については、Resolving Strong Reference Cycles for Closures(クロージャの強循環参照の解消)を参照ください。
GRAMMAR OF A CLOSURE EXPRESSION closure-expression →{
closure-signatureopt statementsopt}
closure-signature → capture-listopt closure-parameter-clausethrows
opt function-resultoptin
closure-signature → capture-listin
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)
_暗黙メンバ式_は、型推論によって暗黙的に型を決定できるコンテキストにおいて、列挙ケースや型メソッドなどの型のメンバにアクセスするための省略記法です。形式は次のとおりです:

暗黙メンバ式
例えば:
var x = MyEnumeration.someValue
x = .anotherValue
推論された型がオプショナルの場合は、暗黙メンバ式にオプショナルでない型のメンバを使用することもできます。
var someOptional: MyEnumeration? = .someValue
暗黙メンバ式の後にPostfix Expressions(後置式)でリストされている後置演算子またはその他の後置構文を続けることができます。これは_暗黙メンバ式チェーン_と呼ばれます。全ての後置式チェーンで同じ型を持つことが一般的ですが、最低限の要件として、暗黙メンバ式チェーン全体がそのコンテキストで暗黙的に推論される型と互換性がある必要があります。具体的には、暗黙的に推論される型がオプショナルの場合は、オプショナル以外の型の値を使用でき、クラス型 の場合、そのサブクラスを使用できます。例えば:
class SomeClass {
static var shared = SomeClass()
static var sharedSubclass = SomeSubclass()
var a = AnotherClass()
}
class SomeSubclass: SomeClass { }
class AnotherClass {
static var s = SomeClass()
func f() -> SomeClass { return AnotherClass.s }
}
let x: SomeClass = .shared.a.f()
let y: SomeClass? = .shared
let z: SomeClass = .sharedSubclass
上記のコードでは、
x
の型はそのコンテキストから暗黙的に推論された型と正確に一致し、y
の型は Someclass
から SomeClass?
に変換され、z
の型は SomeSubclass
から SomeClass
に変換されます。_括弧で囲まれた式_は、括弧で囲まれた式で構成されます。式を明示的にグループ化することで、括弧を使用して操作の優先順位を指定できます。括弧のグループ化は式の型を変更しません(例:
(1)
はただの Int
です。タプル式は、括弧で囲まれた式のカンマ区切りのリストで構成されています。各式は、コロン(
:
)で区切られ、その前に識別子を指定することもできます。形式は次のとおりです:
タプル式
_タプル式_の各識別子は、タプル式の範囲内で一意な必要があります。ネストしたタプル式では、同じレベルでネスト識別子を一意にする必要があります。例えば、
(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
ワイルドカード式は、代入中に値を明示的に無視するために使用されます。例えば、次の代入式
10
は x
に代入されますが、20
は無視されています:(x, _) = (10, 20)
// x は 10 で 20 は 無視されます
GRAMMAR OF A WILDCARD EXPRESSION wildcard-expression →_
_KeyPath 式_は、型のプロパティまたはサブスクリプトを参照します。key-value observing などのような、動的プログラミングのタスクで KeyPath 式を使用します。次の形式があります:

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

Selector 式
メソッド名とプロパティ名は、Objective-C ランタイムで使用可能なメソッドまたはプロパティを参照する必要があります。セレクタ式の値は
Selector
型のインスタンスです。例えば:class SomeClass: NSObject {
@objc let property: String
@objc(doSomethingWithInt:)
func doSomething(_ x: Int) { }
init(property: String) {
self.property = property
}
}
let selectorForMethod = #selector(SomeClass.doSomething(_:))
let selectorForPropertyGetter = #selector(getter: SomeClass.property)
プロパティの get のセレクタを作成すると、プロパティ名は変数または定数プロパティを参照できます。対照的に、set のセレクタを作成すると、プロパティ名は変数プロパティのみ参照しなければなりません。
method name は、同じ名前でシグネチャが異なるメソッド間の曖昧さを軽減するために
as
演算子と一緒にグループ化するための括弧を含めることができます。例えば:extension SomeClass {
@objc(doSomethingWithString:)
func doSomething(_ x: String) { }
}
let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void)
セレクタが実行時ではなくコンパイル時に作成されるため、コンパイラはメソッドまたはプロパティが存在すること、およびそれらが 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)
KeyPath 文字列式を使用すると、Key-Value Coding や Key-Value Observing API で使用するために、Objective-C のプロパティを参照するための文字列にアクセスできます。形式は次のとおりです:

Key-Path文字列式
property name は、Objective-C ランタイムで使用可能なプロパティを参照する必要があります。コンパイル時には、KeyPath 文字列式は文字列リテラルに置き換えられます。例えば:
class SomeClass: NSObject {
@objc var someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
}
}
let c = SomeClass(someProperty: 12)
let keyPath = #keyPath(SomeClass.someProperty)
if let value = c.value(forKey: keyPath) {
print(value)
}
// 12
クラス内で KeyPath 文字列式を使用すると、クラス名なしでプロパティ名だけを書くことでそのクラスのプロパティを参照できます。
extension SomeClass {
func getSomeKeyPath() -> String {
return #keyPath(someProperty)
}
}
print(keyPath == c.getSomeKeyPath())
// true
KeyPath 文字列は、実行時ではなくコンパイル時に作成されているため、コンパイラはプロパティが存在すること、およびそのプロパティが Objective-C ランタイムに公開されていることを確認できます。
Objective-C API とやり取りする Swift コードで KeyPath を使用する方法の詳細については、Using Objective-C Runtime Features in Swiftを参照ください。Key-Value Coding と Key-Value Observing については、Key-Value Coding Programming GuideとKey-Value Observing Programming Guideを参照ください。