Swift 5.3 日本語化計画 : Swift 5.3
式
Swift では、式には4種類があります:接頭辞式、二項式、一次式、そして接尾辞式です。式を評価すると値が返るか、副作用を起こすか、またはその両方です。
接頭辞と二項式を使用すると、演算子は、より小さな式になります。一次式は、概念的には、式の最も簡単な種類であり、それらは値にアクセスする方法を提供します。接尾辞式は、接頭辞と二項式のように、関数呼び出しとメンバへのアクセスのような、接尾辞を使用して、より複雑な式をビルドできます。それぞれの種類の式は、以下のセクションで詳細に記載します。
expression → try-operator opt prefix-expression binary-expressions opt
expression-list → expression | expression , expression-list
接頭辞式
接頭辞式 は式に、オプションの接頭辞演算子を組み合わせたものです。接頭辞演算子は、一つの引数を取り、それらに式が続きます。
これらの演算子の動作については、基本演算子 および 高度な演算子 を参照してください。
Swift 標準ライブラリで提供される演算子については、演算子の宣言 を参照してください。
標準ライブラリの演算子に加え、関数の呼び出し式への in-out 引数として渡される変数の名前の直前に & を使用して下さい。詳細と例を参照するには、In-Out パラメータ をご覧ください。
prefix-expression → prefix-operator opt postfix-expression
prefix-expression → in-out-expression
in-out-expression → & identifier
Try 演算子
try 式 はエラーを throw できる式が続く try 演算子で構成されています。これは以下の形式を持っています。
try
optional の try 式は、エラーを throw できる式が続く try? 演算子で構成されています。これは以下の形式を持っています。
try?
式 がエラーを throw しない場合は、optional の try 式の値は、式 の値を含む optional です。それ以外の場合は、optional の try 式の値は nil です。
強制 try 式 は、エラーを throw できる式が続く try! 演算子で構成されています。これは以下の形式を持っています:
try!
式 がエラーを throw した場合、実行時エラーが生まれます。
二項演算子の左側の式が try, try? または try! でマークされている場合、その演算子は二項式全体に適用されます。つまり、演算子の適用範囲を明示するために、括弧を使用できる、と言う事です。
- sum = try someThrowingFunction() + anotherThrowingFunction()    // try applies to both function calls
- sum = try (someThrowingFunction() + anotherThrowingFunction()) // try applies to both function calls
- sum = (try someThrowingFunction()) + anotherThrowingFunction() // Error: try applies only to the first function call
二項演算子が代入演算子でないか、try 式が括弧で囲まれていない場合は、try 式は、二項演算子の右側に表示できません。
詳細および try, try? 及び try! を使用する方法の例については、エラー処理 を参照してください。
try-operator → try | try ? | try !
二項式
二項式 は、その左側と右側の引数として取る式と挿入辞の二項演算子を組み合わせます。これは以下の形式です:
これらの演算子の動作については、基本演算子 と 高度な演算子 を参照してください。
Swift 標準ライブラリで提供される演算子についての詳細は、演算子の宣言 を参照してください。
binary-expression → binary-operator prefix-expression
binary-expression → assignment-operator try-operator opt prefix-expression
binary-expression → conditional-operator try-operator opt prefix-expression
binary-expression → type-casting-operator
binary-expressions → binary-expression binary-expressions opt
代入演算子
代入演算子 は、与えられた式に新しい値を設定します。これには以下の形式があります:
=
式 の値は、値 を評価して得た値に設定されます。式 がタプルの場合は、値 は同じ数の要素を持つタプルでなければなりません。(ネストしたタプルも許可されます。) 代入は 式 の対応する部分に 値 の各部分から行われます。例えば:
- (a, _, (b, c)) = ("test", 9.45, (12, 3))
- // a is "test", b is 12, c is 3, and 9.45 is ignored
代入演算子は、全く値を返しません。
assignment-operator → =
三項条件演算子
三項条件演算子 は、条件の値に基づいて、与えられた2つの値の1つに評価されます。これは以下の形式です:
? :
条件 が true と評価された場合は、条件演算子は最初の式を評価し、その値を返します。それ以外の場合は、第二式を評価し、その値を返します。未使用の式は評価されません。
三項条件演算子を使用する例については、三項条件演算子 を参照してください。
conditional-operator → ? expression :
型キャスト演算子
型キャスト演算子には4つあり、is 演算子、as 演算子、as? 演算子、そして as! 演算子です。
それらは、以下のような形式です:
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)
- // prints "Function for Int"
- let y: Any = x
- f(y)
- // prints "Function for Any"
- f(x as Any)
- // prints "Function for Any"
ブリッジでは、新しいインスタンスを作成する必要なしに、NSString のような、それに対応する Foundation 型の String のように Swift 標準ライブラリ型の式を使用することができます。ブリッジの詳細については、Foundation 型で作業する を参照してください。
as? 演算子は、指定した 型 に 式 の条件キャストを実行します。as? 演算子は、指定した 型 の optional を返します。実行時に、キャストが成功した場合、式 の値は、optional で包まれ、返されます。そうでない場合、戻り値は nil です。指定した 型 へのキャストが失敗することが保証されているか、成功することが保証されている場合は、コンパイル時エラーが発生します。
as! 演算子は、指定した 型 に 式 の強制キャストを実行します。as! 演算子は optional の型 ではなく、指定した 型 の値を返します。キャストが失敗した場合、実行時エラーが発生します。x as! T の動作は、(x as? T)! の動作と同じです。
型キャストの更なる情報と型キャスト演算子を使用する際の例に付いては、型キャスト を参照してください。
type-casting-operator → is type
type-casting-operator → as type
type-casting-operator → as ? type
type-casting-operator → as ! type
一次式
一次式 は、式の最も基本的な種類です。それらは、接頭辞式、二項式、及び接尾辞式を作るために他のトークンと組み合わせることができ、それら自体で式として使用できます。
primary-expression → identifier generic-argument-clause opt
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
リテラル式
リテラル式 は、通常のリテラル (文字列や数字など) か、配列または辞書リテラル、プレイグラウンドリテラル、または以下の特別なリテラルのいずれかで構成されます。
リテラル | 型 | 値 |
---|---|---|
#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 式の文字列値の形式は module/file であり、ここで、file は式がその中で表示されるファイルの名前であり、module はこのファイルが含まれるモジュールの名前です。#filePath 式の文字列値は、式がその中に表示されるファイルへの完全なファイルシステムパスです。これらの値は両方とも、行制御文 で説明されているように、#sourceLocation によって変更できます。#fileID は、#filePath とは異なり、ソースファイルへのフルパスを埋め込んでいないため、プライバシーが向上し、コンパイルされたバイナリのサイズが小さくなります。テスト、ビルドスクリプト、または出荷プログラムの一部にならないその他のコード以外で #filePath を使用することは避けてください。
#fileID 式を解析するには、モジュール名を最初のスラッシュ (/) の前のテキストとして読み取り、ファイル名を最後のスラッシュの後のテキストとして読み取ります。将来的には、文字列に MyModule/some/disambiguation/MyFile.swift などの複数のスラッシュが含まれる可能性があります。
関数の内部では、#function の値は、その関数の名前であり、メソッドの内部ではそのメソッドの名前であり、プロパティのゲッタまたはセッタの内部では、そのプロパティの名前であり、init や subscript のような特別なメンバの内部では、そのキーワードの名前であり、またファイルのトップレベルでは、現在のモジュールの名前です。
関数またはメソッドのパラメータのデフォルトの値として使用する場合、デフォルト値の式を呼び出しサイトで評価した場合、特別なリテラルの値が決定されます。
- func logFunctionName(string: String = #function) {
- print(string)
- }
- func myFunction() {
- logFunctionName() // Prints "myFunction()".
- }
配列リテラル は、値の順序付けられた集合です。これは以下の形式です:
[, , ]
配列の最後の式は、オプションのカンマで続けることができます。配列リテラルの値は、[T] 型であり、ここで T はその内部の式の型です。複数の型の式がある場合、T は、最も近い共通のスーパータイプです。空の配列リテラルは、角括弧の空のペアを使用して書かれ、指定した型の空の配列を作成するために使用できます。
辞書リテラル は、キーと値のペアの順不同の集合です。これは以下の形式です:
[: ,: ,]
辞書の最後の式は、オプションのカンマで続けられます。辞書リテラルの値は [Key: Value] 型ですが、ここで Key は、そのキー式の型であり、Value はその値の式の型です。複数の型の式がある場合は、Key と Value は、それぞれの値の最も近い共通のスーパータイプです。空の辞書リテラルは、空の配列リテラルと区別するために、一対の括弧の内側のコロンとして書かれます。([:])。指定したキーと値の型の空の辞書リテラルを作成して空の辞書リテラルを使用できます。
プレイグラウンドのリテラル は、プログラムエディタ内部の色、ファイル、または画像のインタラクティブな表現を作成するために Xcode で使用されます。Xcode の外部のプレーンテキストでのプレイグラウンドのリテラルは特別なリテラル構文を用いて表現されます。
Xcode でのプレイグラウンドのリテラルの使用方法については、Xcode のヘルプの カラー、ファイル、イメージリテラルの追加 を参照してください。
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-items opt ]
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[ ]
self( )
self. init( )
イニシャライザ、サブスクリプト、またはインスタンス・メソッドでは、self は、それが発生する型の現在のインスタンスを参照します。型メソッドでは、self は、それが発生する現在の型を参照します。
self 式は、スコープ内に同じ名前の別の変数がある場合、関数のパラメータのように、区別する方法を提供し、メンバにアクセスする際にスコープを指定するために使用されます。例えば:
- class SomeClass {
- var greeting: String
- init(greeting: String) {
- self.greeting = greeting
-         }
- }
値型の変異メソッドでは、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)
- }
- }
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
スーパークラス式
スーパークラス式 を使うと、そのスーパークラスと、クラスを相互作用することができます。それは、以下のいずれかの形式です:
super.
super[]
super.init()
最初の形式は、スーパークラスのメンバにアクセスするために使用されます。第2の形式は、スーパークラスのサブスクリプトの実装にアクセスするために使用されます。3番目の形式は、スーパークラスのイニシャライザにアクセスするために使用されます。
サブクラスは、それらのスーパークラスでの実装を利用するメンバ、サブスクリプト、およびイニシャライザの実装で、スーパークラス式を使用できます。
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
クロージャ式
クロージャ式 は、ラムダ または他のプログラミング言語で 無名関数 としても知られているクロージャを作成します。関数宣言と同様に、クロージャは文を含み、それが囲むスコープから定数と変数をキャプチャします。これは以下の形式です:
{ ) -> in
}
パラメータ は、関数の宣言 で説明したように、関数の宣言におけるパラメータと同じ形式を持っています。
クロージャを、より簡潔に書くことができるいくつかの特別な形式があります。
- クロージャはそのパラメータの型、その戻り値の型、または両方を省略できます。パラメータ名と両方の型を省略した場合、文の前の 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()
- // Prints "0 10"
2つの異なる名前のついたもの a と、周囲のスコープ内の変数と、クロージャのスコープ内の定数で、一つだけの名前の付いた変数の b があります。内側のスコープ内の a はクロージャが作成される時、外側のスコープ内の a の値で初期化されますが、それらの値は、いかなる特別な方法でも接続されてはいません。これは、外側のスコープ内の a の値への変化は、内側のスコープ内の a の値に影響を与えないことを意味し、またクロージャ内部の a への変更がクロージャ外側の a の値に影響を与えない事を意味します。これとは対照的に、一つだけ b という変数があり、外側のスコープでの b であり、クロージャの内側または外側からの変更は、両方の場所から見えます。
キャプチャされた変数の型が参照する意味がある場合は、この区別は見えません。たとえば、以下のコードでは 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()
- // Prints "10 10"
式の値の型がクラスである場合、弱いまたは所有されない参照で式の値をキャプチャするには、キャプチャ・リストの式を weak または unowned でマークできます。
- myFunction { print(self.title) }                                // implicit strong capture
- myFunction { [self] in print(self.title) }                   // explicit strong capture
- myFunction { [weak self] in print(self!.title) }        // weak capture
- myFunction { [unowned self] in print(self.title) }    // unowned capture
また、キャプチャリストの名前の付いた値に任意の式を結合する事もできます。式は、クロージャが作成された時評価され、値は指定された強度でキャプチャされます。例えば:
- // Weak capture of "self.parent" as "parent"
- myFunction { [weak parent = self.parent] in print(parent!.title) }
クロージャ式の詳細と例については、クロージャ式 を参照してください。キャプチャリストの詳細と例については、クロージャの強い循環参照の解決 を参照してください。
closure-expression → { closure-signature opt statements opt }
closure-signature → capture-list opt closure-parameter-clause throws opt function-result opt 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-annotation opt
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-specifier opt expression
capture-specifier → weak | unowned | unowned(safe) | unowned(unsafe)
暗黙のメンバ式
暗黙のメンバ式 は、型推論が暗黙の型を決定できる文脈で、列挙型の case や型メソッドのように型のメンバにアクセスするための近道の方法です。これは以下の形式です:
.
例えば:
- var x = MyEnumeration.someValue
- x = .anotherValue
implicit-member-expression → . identifier
括弧で囲まれた式
括弧で囲まれた式 は、括弧で囲まれた式で構成されています。明示的にグループ化した式で演算の優先順位を指定するために、括弧を使用できます。グループ化する括弧は、式の型を変更しません。例えば、(1) の型は、単純に Int です。
parenthesized-expression → ( expression )
タプル式
タプル式 は括弧で囲まれた式の、コンマ区切りのリストで構成されています。それぞれの式は、コロン (:) で区切られた、その前の任意の識別子を持つことができます。これは以下の形式を持っています。
( : , : , )
タプル式の各識別子は、タプル式のスコープ内で一意でなければなりません。ネストされたタプル式では、同じレベルのネストする識別子は一意でなければなりません。たとえば、ラベル a が同じレベルで 2 回表示されるため、(a: 10、a: 20) は無効です。ただし、(a: 10,b:(a: 1, x: 2)) は有効です。a は 2 回出現しますが、外側のタプルに 1 回、内側のタプルに 1 回出現するからです。
タプル式はゼロ個の式を含むことができ、または2つ以上の式を含むことができます。カッコ内の単一の式は括弧で囲まれた式です。
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 is 10, and 20 is ignored
wildcard-expression → _
キーパス式
キーパス式 は、ある型のプロパティまたはサブスクリプトを参照します。キー値監視などの動的プログラミングタスクでは、キーパス式を使用して下さい。それらは以下の形式です:
\.
型名 (type name) は、String,[Int], または Set<Int> などの汎用パラメータを含む具体的な型の名前です。
パス (path) は、プロパティ名、サブスクリプト、optional の連鎖式、および強制開封式で構成されます。これらのキーパス成分のそれぞれは、任意の順序で、必要に応じて何度も繰り返すことができます。
コンパイル時に、キーパス式は KeyPath クラスのインスタンスに置き換えられます。
キーパスを使用して値にアクセスするには、すべての型で使用可能な subscript(keyPath:) サブスクリプトにキーパスを渡します。例えば:
- struct SomeStructure {
- var someValue: Int
- }
- let s = SomeStructure(someValue: 12)
- let pathToProperty = \SomeStructure.someValue
- let value = s[keyPath: pathToProperty]
- // value is 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 を参照して ID キーパス ( \.self) を作成できます。ID キーパスはインスタンス全体を参照するため、これを使用して単一の手順で変数に格納されているすべてのデータにアクセスして変更できます。例えば:
- var compoundValue = (a: 1, b: 2)
- // Equivalent to compoundValue = (a: 10, b: 20)
- compoundValue[keyPath: \.self] = (a: 10, b: 20)
パス (path) には、プロパティ値のプロパティを参照する複数のプロパティ名をピリオドで区切って含めることができます。このコードでは、キーパス式 \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 is 24
サブスクリプトのパラメータ型が Hashable プロトコルに準拠しているかぎり、パス(path) には括弧を使用したサブスクリプトを含めることができます。この例では、キーパスのサブスクリプトを使用して配列の 2 番目の要素にアクセスします。
- let greetings = ["hello", "hola", "bonjour", "안녕"]
- let myGreeting = greetings[keyPath: \[String].[1]]
- // myGreeting is 'hola'
サブスクリプトで使用される値は、名前付きの値またはリテラルにすることができます。値は、値セマンティクスを使用してキーパスにキャプチャされます。以下のコードでは、key-path 式とクロージャの両方で変数 index を使用して、greetings 配列の 3 番目の要素にアクセスします。index が変更されると、キーパス式はまだ 3 番目の要素を参照しますが、クロージャは新しいインデックスを使用します。
- var index = 2
- let path = \[String].[index]
- let fn: ([String]) -> String = { strings in strings[index] }
- print(greetings[keyPath: path])
- // Prints "bonjour"
- print(fn(greetings))
- // Prints "bonjour"
- // Setting 'index' to a new value doesn't affect 'path'
- index += 1
- print(greetings[keyPath: path])
- // Prints "bonjour"
- // Because 'fn' closes over 'index', it uses the new value
- print(fn(greetings))
- // Prints "안녕"
パス(path) には、optional の連鎖と強制開封を使用できます。このコードでは、キーパスで optional の連鎖を使用して、optional の文字列のプロパティにアクセスしています。
- let firstGreeting: String? = greetings.first
- print(firstGreeting?.count as Any)
- // Prints "Optional(5)"
- // Do the same thing using a key path.
- let count = greetings[keyPath: \[String].first?.count]
- print(count as Any)
- // Prints "Optional(5)"
キーパスの成分を混在させて一致させることで、ある型のなかで深くネストされた値にアクセスできます。以下のコードは、これらの成分を結合するキーパス式を使用して、配列の辞書の異なる値とプロパティにアクセスしています。
- let interestingNumbers = ["prime": [2, 3, 5, 7, 11, 13, 15],
-   "triangular": [1, 3, 6, 10, 15, 21, 28],
-   "hexagonal": [1, 6, 15, 28, 45, 66, 91]]
- print(interestingNumbers[keyPath: \[String: [Int]].["prime"]] as Any)
- // Prints "Optional([2, 3, 5, 7, 11, 13, 15])"
- print(interestingNumbers[keyPath: \[String: [Int]].["prime"]![0]])
- // Prints "2"
- print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count])
- // Prints "7"
- print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth])
- // Prints "64"
通常は関数またはクロージャを提供する文脈で、キーパス式を使用できます。具体的には、関数または型のクロージャ (SomeType) -> Value の代わりに、そのルート型が SomeType であり、そのパス (path) が 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),
- ]
- // Both approaches below are equivalent.
- let descriptions = toDoList.filter(\.completed).map(\.description)
- let descriptions2 = toDoList.filter { $0.completed }.map { $0.description }
キーパス式の副作用は、式が評価される点でのみ評価されます。たとえば、キーパス式のサブスクリプト内で関数呼び出しを行う場合、関数は、キーパスが使用されるたびにではなく、式の評価の一部として 1 回だけ呼び出されます。
- func makeIndex() -> Int {
- print("Made an index")
- return 0
- }
- // The line below calls makeIndex().
- let taskKeyPath = \[Task][makeIndex()]
- // Prints "Made an index"
- // Using taskKeyPath doesn't call makeIndex() again.
- let someTask = toDoList[keyPath: taskKeyPath]
Objective-C の API と相互作用するコードでキーパスを使用する方法の詳細については、Swift で Objective-C 実行時機能を使用する を参照して下さい。キー値コーディングとキー値監視については、キー値コーディングプログラミングガイド (原文はこちら) および キー値監視プログラミングガイド (原文はこちら) を参照してください。
キー値コーディング 及び キー値監視プログラミングガイド に関しては、訳出しない事にしました。これらの文書はすでに Obsolete だからです。
key-path-expression → \ type opt . key-path-components
key-path-components → key-path-component | key-path-component. key-path-components
key-path-component → identifier key-path-postfixes opt | key-path-postfixes
key-path-postfixes → key-path-postfix key-path-postfixes opt
key-path-postfix → ? | ! | self | [ function-call-argument-list ]
セレクタ式
セレクタ式では、Objective-C でのプロパティのゲッタやセッタ、またはメソッドを参照するために使用されるセレクタにアクセスできます。これは、以下の形式です。
#selector()
#selector(getter : )
#selector(setter : )
メソッド名 (method name) と プロパティ名 (property name) は、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)
プロパティのゲッタ用のセレクタを作成する場合、プロパティ名 は、変数または定数プロパティへの参照になることができます。それに対し、プロパティのセッタ用のセレクタを作成するときには、プロパティ名 は、変数プロパティのみへの参照でなければなりません。
メソッド名 は、as 演算子と同様に、グループ化するのに括弧を含める事ができ、名前を共有するが異なる型のシグナチャを持つメソッドの間で明確にすることができます。例えば:
- extension SomeClass {
- @objc(doSomethingWithString:)
- func doSomething(_ x: String) { }
- }
- let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void)
セレクタは、実行時にではなく、コンパイル時に作成されるため、コンパイラは、メソッドやプロパティが存在し、それらは Objective-C 実行時に expose されている事を確認できます。
Objective-C の API と相互対話する Swift コードでのセレクタを使用する方法の詳細については、Swift で Objective-C 実行時機能を使用する を参照してください。
selector-expression → #selector ( expression )
selector-expression → #selector ( getter : expression )
selector-expression → #selector ( setter : expression )
キーパス文字列式
キーパス文字列式を使用すると、Objective-C でのプロパティを参照するために使用される文字列にアクセスし、キー値コーディングおよびキー値監視 API で使用できます。これは以下の形式を持ちます:
#keyPath(
プロパティ名 (property name) は、Objective-C 実行時環境で使用可能なプロパティへの参照でなければなりません。コンパイル時に、キーパス文字列式は文字列リテラルに置き換えられます。例えば:
- 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)
- }
- // Prints "12"
クラス内でキーパス文字列式を使用する場合は、クラス名なしで、プロパティ名だけを記述することで、そのクラスのプロパティを参照できます。
- extension SomeClass {
- func getSomeKeyPath() -> String {
- return #keyPath(someProperty)
- }
- }
- print(keyPath == c.getSomeKeyPath())
- // Prints "true"
キーパス文字列は実行時ではなくコンパイル時に作成されるため、コンパイラはプロパティが存在し、プロパティが Objective-C 実行時環境に expose されていることを確認できます。
Objective-C API と相互対話する Swift コードでキーパスを使用する方法の詳細については、Swift で Objective-C 実行時機能を使用する を参照して下さい。キー値コーディングとキー値監視については、キー値コーディングプログラミングガイド (原文はこちら) および キー値監視プログラミングガイド (原文はこちら) を参照してください。
key-path-string-expression → #keyPath ( expression )
接尾辞の式
接尾辞の式 は、接尾辞演算子または他の接尾辞構文を式に当てはめて形成されます。構文的には、すべての一次式は、また接尾辞式です。
これらの演算子の動作については、基本演算子 および 高度な演算子 を参照してください。
Swift の標準ライブラリで提供される演算子の詳細については、演算子の宣言 を参照してください。
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
関数呼び出し式
関数呼び出し式 は、カッコ内の関数の引数をカンマで区切ったリストが続く、関数名で構成されています。関数呼び出し式は、以下のような形式です。
(, )
関数名 は、式の値が関数の型である、任意の式でありえます。
関数の定義が、そのパラメータの名前を含んでいる場合は、関数呼び出しには、コロン (:) で区切られた引数値の前に、名前を含んでいなければなりません。この種の関数呼び出し式の形式は以下のとおりです。
(: , : )
関数呼び出し式は、閉じ括弧の直後にクロージャ式の形式が末尾に続くクロージャを含めることができます。末尾に続くクロージャは、最後の括弧内の引数の後に追加された、関数への引数として理解されます。最初のクロージャ式にはラベルが付いていません。追加のクロージャ式の前には、その引数ラベルが付いています。以下の例は、末尾のクロージャ構文を使用する関数呼び出しと使用しないものの同等のバージョンを示しています。
- // someFunction takes an integer and a closure as its arguments
- someFunction(x: x, f: {$0 == 13})
- someFunction(x: x) {$0 == 13}
- // anotherFunction takes an integer and two closures as its arguments
- anotherFunction(x: x, f: { $0 == 13 }, g: { print(99) })
- anotherFunction(x: x) { $0 == 13 } g: { print(99) }
- // someFunction takes a closure as its only argument
- myData.someMethod( ) {$0 == 13}
- myData.someMethod {$0 == 13}
引数に、末尾に続くクロージャを含めるためには、コンパイラは関数のパラメータを左から右に調べます。以下のように:
末尾に続く クロージャ | パラメータ | アクション |
ラベル付き | ラベル付き | ラベルが同じである場合、クロージャはパラメータと一致します。それ以外の場合、パラメータはスキップされます。 |
ラベル付き | ラベルなし | パラメータはスキップされます。 |
ラベルなし | ラベル付きまたはラベルなし | 以下に定義するように、パラメータが構造的に関数型に類似している場合、クロージャはパラメータと一致します。それ以外の場合、パラメータはスキップされます。 |
末尾に続くクロージャは、一致するパラメータの引数として渡されます。スキャンするプロセス中にスキップされたパラメータには、それに渡される引数はありません。たとえば、デフォルトのパラメータを使用できます。一致するものを見つけた後、スキャンは次の末尾に続くクロージャと次のパラメータで続行されます。一致するプロセスの最後に、すべての末尾に続くクロージャが一致しなければなりません。
パラメータが in-out パラメータではなく、パラメータが以下のいずれかである場合、パラメータは 構造的に 関数型に 似ています。
- (Bool) -> Int のように、型が関数型であるパラメータ
- その包み込まれた式の型が @autoclosure () -> ((Bool) -> Int) のような関数型であるオートクロージャパラメータ
- その配列要素型が ((Bool) -> Int).. のような関数型である可変個引数パラメータ
- Optional<(Bool) -> Int> のように、その型が optional の 1 つ以上の層で包み込まれているパラメータ。
- (Optional <(Bool) -> Int>).. のように、その型がこれらの許可された型を組み合わせたパラメータ。
末尾に続くクロージャが、その型が関数型に構造的に似ているが関数ではないパラメータと一致する場合、クロージャは必要に応じて包み込まれます。たとえば、パラメータの型が optional の型である場合、クロージャは自動的に Optional に包み込まれます。
この一致を右から左に実行していた、5.3 より前のバージョンの Swift からのコードの移行を容易にするために、コンパイラは左から右と右から左の両方の順序をチェックします。スキャン方向によって異なる結果が生成される場合は、古い右から左への順序が使用され、コンパイラは警告を生成します。Swift の将来のバージョンでは、常に左から右の順序が使用されます。
- typealias Callback = (Int) -> Int
- func someFunction(firstClosure: Callback? = nil,
- secondClosure: Callback? = nil) {
- let first = firstClosure?(10)
- let second = secondClosure?(20)
- print(first ?? "-", second ?? "-")
- }
- someFunction() // Prints "- -"
- someFunction { return $0 + 100 } // Ambiguous
- someFunction { return $0 } secondClosure: { return $0 } // Prints "10 20"
上記の例では、"Ambiguous" とマークされた関数呼び出しは "-120" を出力し、Swift 5.3 上ではコンパイラ警告を生成します。Swift の将来のバージョンでは、"110-" が出力されるでしょう。
クラス、構造体、または列挙型は、特別な名前のメソッド で説明したように、いくつかのメソッドの 1 つを宣言することにより、関数呼び出し構文のシンタックスシュガーを有効にできます。
function-call-expression → postfix-expression function-call-argument-clause
function-call-expression → postfix-expression function-call-argument-clause opt trailing-closure
function-call-argument-clause → ( ) | ( function-call-argument-list )
function-call-argument-list → function-call-argument | function-call-argument , function-call-argument-list
function-call-argument → expression | identifier : expression
function-call-argument → operator | identifier : operator
trailing-closure → closure-expression labeled-trailing-closures opt
labeled-trailing-closures → labeled-trailing-closure labeled-trailing-closures opt
labeled-trailing-closure → identifier : closure-expression
イニシャライザ式
イニシャライザ式 は、型のイニシャライザへのアクセスを提供します。これは以下の形式です:
.init()
型の新しいインスタンスを初期化する関数呼び出し式でイニシャライザ式を使用できます。また、スーパークラスのイニシャライザにデリゲートするイニシャライザ式も使用できます。
- class SomeSubClass: SomeSuperClass {
- override init() {
- // subclass initialization goes here
- super.init()
- }
- }
関数のように、イニシャライザは値として使用できます。例えば:
- // Type annotation is required because String has multiple initializers.
- let initializer: (Int) -> String = String.init
- let oneTwoThree = [1, 2, 3].map(initializer).reduce("", +)
- print(oneTwoThree)
- // Prints "123"
名前で型を指定する場合は、イニシャライザ式を使用せずに、型イニシャライザにアクセスできます。他のすべての場合では、イニシャライザ式を使用しなければなりません。
- let s1 = SomeType.init(data: 3)    // Valid
- let s2 = SomeType(data: 1)          // Also valid
- let s3 = type(of: someValue).init(data: 7)    // Valid
- let s4 = type(of: someValue)(data: 5)           // Error
initializer-expression → postfix-expression. init
initializer-expression → postfix-expression. init ( argument-names )
明示的なメンバ式
明示的なメンバ式 は、名前付きの型、タプル、またはモジュールのメンバへのアクセスを可能にします。それは、項目とそのメンバの識別子との間のピリオド (.) で構成されています。
.
名前付きの型のメンバは、型の宣言または拡張機能の一部として命名されます。例えば:
- class SomeClass {
- var someProperty = 42
- }
- let c = SomeClass()
- let y = c.someProperty // Member access
タプルのメンバは、表示される順にゼロから始まる整数を使って、暗黙のうちに名前が付けられます。例えば:
- var t = (10, 20, 30)
- t.0 = t.1
- // Now t is (20, 20, 30)
モジュールのメンバは、そのモジュールの最上位レベルの宣言にアクセスします。
dynamicMemberLookup 属性で宣言された型には、属性 で説明したように、実行時に検索されるメンバが含まれます。
引数の名前によってのみその名前が異なるメソッドまたはイニシャライザを区別するには、コロン(:) が続く各引数名で、括弧内の引数名を含めて下さい。名前のない引数ではアンダースコア(_) を書きます。オーバーロードされたメソッド間を区別するためには、型注釈を使用して下さい。例えば:
- class SomeClass {
- func someMethod(x: Int, y: Int) {}
- func someMethod(x: Int, z: Int) {}
- func overloadedMethod(x: Int, y: Int) {}
- func overloadedMethod(x: Int, y: Bool) {}
- }
- let instance = SomeClass()
- let a = instance.someMethod                // Ambiguous
- let b = instance.someMethod(x:y:)        // Unambiguous
- let d = instance.overloadedMethod        // Ambiguous
- let d = instance.overloadedMethod(x:y:)    // Still ambiguous
- let d: (Int, Bool) -> Void = instance.overloadedMethod(x:y:)    // Unambiguous
ピリオドが行の先頭に表示されている場合、それは暗黙のメンバ式としてではなく、明示的なメンバ式の一部として理解されます。たとえば、以下のリストは、連鎖したメソッドの呼び出しが複数の行にわたって分割されている事を示します。
- let x = [10, 3, 20, 15, 4]
- .sorted()
- .filter { $0 > 5 }
- .map { $0 * 100 }
explicit-member-expression → postfix-expression . decimal-digits
explicit-member-expression → postfix-expression . identifier generic-argument-clause opt
explicit-member-expression → postfix-expression . identifier ( argument-names )
argument-names → argument-name argument-names opt
argument-name → identifier :
接尾辞の self 式
接尾辞の self 式は、式または型の名前から成り立ち、直後に .self が続きます。これには、以下の形式があります。
.self
.self
最初の形式は 式 の値に評価します。たとえば、x.self は、x と評価します。
二番目の形式は、型 の値に評価します。値としての型にアクセスするにはこの形式を使用して下さい。例えば、SomeClass.self は SomeClass 型自体に評価するため、型レベルの引数を受け取る関数やメソッドにそれを渡すことができます。
postfix-self-expression → postfix-expression . self
サブスクリプト式
サブスクリプト式 は対応するサブスクリプト宣言のゲッタとセッタを使用して、サブスクリプトアクセスを提供します。これは以下の形式です:
[ ]
サブスクリプト式の値を評価するために、式 の型のサブスクリプトゲッタは、サブスクリプト・パラメータとして渡された インデックス式 で呼び出されます。その値を設定するためには、サブスクリプト・セッタも同様に呼び出されます。
サブスクリプト宣言の詳細については、プロトコルサブスクリプト宣言 を参照してください。
subscript-expression → postfix-expression [ function-call-argument-list ]
強制値の式
強制値の式 は、nil でないと確信される、optional の値を開封します。これには以下の形式があります:
!
式 の値が nil でない場合、optional の値は開封され、対応する optional でない型を返します。それ以外の場合は、実行時エラーが発生します。
強制値の式の開封された値は、値自体を変異させることによってか、あるいは値のメンバの一つに代入することによってか、どちらかで変更できます。例えば:
- var x: Int? = 0
- x! += 1
- // x is now 1
- var someDictionary = ["a": [1, 2, 3], "b": [10, 20]]
- someDictionary["a"]![0] = 100
- // someDictionary is now ["a": [100, 2, 3], "b": [10, 20]]
forced-value-expression → postfix-expression !
Optional の連鎖式
optional の連鎖式 は、接尾辞の式で optional の値を使用するための簡単な構文を提供します。これは以下の形式です:
?
接尾辞の ? 演算子は、式の値を変更せずに式から optional の連鎖式を作ります。
Optional の連鎖式は接尾辞式内に表示されなければならず、接尾辞式は、特別な方法での評価が起こります。optional の連鎖式の値が nil である場合、接尾辞式の他のすべての演算は無視され、全体の接尾辞式は nil に評価されます。optional の連鎖式の値が nil でない場合は、optional の連鎖式の値は開封され、接尾辞式の残りの部分を評価するために使用されます。いずれの場合も、接尾辞式の値はまだ optional の型のままです。
optional の連鎖式を含む接尾辞式が、他の接尾辞式内にネストされている場合、最も外側の式だけが、optional の型を返します。以下の例では、c が nil でない場合、その値は開封されて、 .property を評価するために使用され、その値は .performAction() を評価するために使用されます。全体の式 c?.property.performAction() は optional の型の値を持っています。
- var c: SomeClass?
- var result: Bool? = c?.property.performAction()
以下の例は、optional の連鎖を使用せずに上記の例の動作を示します。
- var result: Bool?
- if let unwrappedC = c {
- result = unwrappedC.property.performAction()
- }
optional の連鎖式の開封された値は、値自体を変異させることによってか、あるいは値のメンバの一つに代入することによってかのいずれかによって、変更できます。optional の連鎖式の値が nil である場合、代入演算子の右辺の式は評価されません。例えば:
- func someFunctionWithSideEffects() -> Int {
- return 42 // No actual side effects.
- }
- var someDictionary = ["a": [1, 2, 3], "b": [10, 20]]
- someDictionary["not here"]?[0] = someFunctionWithSideEffects()
- // someFunctionWithSideEffects is not evaluated
- // someDictionary is still ["a": [1, 2, 3], "b": [10, 20]]
- someDictionary["a"]?[0] = someFunctionWithSideEffects()
- // someFunctionWithSideEffects is evaluated and returns 42
- // someDictionary is now ["a": [42, 2, 3], "b": [10, 20]]
optional-chaining-expression → postfix-expression ?
前:型 次:文
トップへ
トップへ
トップへ
トップへ