式(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!、がマークされている場合、その演算子はバイナリ式全体に適用されます。一方で、括弧(())を使用して、演算子の適用範囲を明示することもできます。

//両方の関数呼び出しに適用されます
sum = try someThrowingFunction() + anotherThrowingFunction()

//両方の関数呼び出しに適用されます
sum = try (someThrowingFunction() + anotherThrowingFunction())

//エラー:最初の関数呼び出しにのみ適用されます
sum = (try someThrowingFunction()) + anotherThrowingFunction()

バイナリ演算子が代入演算子の場合、または 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 演算子がマークされている場合、その演算子はバイナリ式全体に適用されます。ただし、括弧を使用して、演算子の適用範囲について明示することができます。

//両方の関数呼び出しに適用されます
sum = await someAsyncFunction() + anotherAsyncFunction()

//両方の関数呼び出しに適用されます
sum = await (someAsyncFunction() + anotherAsyncFunction())

//エラー:最初の関数呼び出しにのみ適用されます
sum = (await someAsyncFunction()) + anotherAsyncFunction()

バイナリ演算子が代入演算子の場合、または 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 の中の対応する部分に対して行われます。例えば:

(a, _, (b, c)) = ("test", 9.45, (12, 3))
// a は"test"、 b は 12、 c は 3、 9.45 は無視されます

代入演算子は任意の値を返しません。

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 :

Type-Casting Operators(型キャスト演算子)

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)! の挙動と同じです。

型キャストの詳細や型キャスト演算子を使用する例については、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 のような特別なメンバ内では、そのキーワード名、およびファイルのトップレベルでは、現在のモジュール名です。

関数またはメソッドのパラメータのデフォルト値として使用すると、呼び出し側でデフォルト値の式が評価され、特別なリテラル値が決定します。

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 リテラルには、特別なリテラル構文を使用します。

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式

イニシャライザ、サブスクリプト、またはインスタンスメソッドでは、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

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

スーパークラス式は、クラスがスーパークラスとやり取りすることを可能にします。次のいずれかの形式があります:

スーパークラス式

最初の形式はスーパークラスのメンバにアクセスするために使用されます。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

クロージャ式(Closure Expression)

クロージャ式は、他のプログラミング言語では、ラムダまたは匿名関数とも呼ばれているクロージャを作成します。関数宣言のように、クロージャには文が含まれており、その囲まれている範囲から定数と変数をキャプチャします。形式は次のとおりです:

クロージャ式

Function Declaration(関数宣言)で説明されているように、parametersは関数宣言内のパラメータと同じ形式です。

クロージャをより簡潔に書くことができるいくつかの特別な形式があります:

  • クロージャは、そのパラメータ、戻り値の型、またはその両方の型を省略できます。パラメータ名と型の両方を省略する場合は、文の前の 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 }

関数の引数としてクロージャを渡す方法については、Function Call Expression(関数呼び出し式)を参照ください。

クロージャ式は、関数呼び出しの一部としてすぐにクロージャを使用するときなど、可変または定数に格納されることなく使用できます。上記のコードの myFunction に渡されたクロージャ式は、即時に使用される例です。その結果、クロージャ式がエスケープか非エスケープかは、式の周囲のコンテキストによって異なります。クロージャ式は、即時に呼ばれるか、非エスケープ関数の引数として渡されると、非エスケープです。それ以外の場合、クロージャ式はエスケープです。

クロージャのエスケープの詳細については、Escaping Closures(エスケープクロージャ)を参照ください。

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

デフォルトでは、クロージャ式は、、周囲のスコープの定数と変数を強い参照を持ってキャプチャします。キャプチャリストを使用して、クロージャ内で値をキャプチャする方法を明示的に制御できます。

キャプチャリストは、パラメータのリストの前に、角括弧([])で囲まれた式のカンマ(,)区切りのリストとして書かれます。キャプチャリストを使用する場合は、パラメータ名、パラメータ型、および戻り値の型を省略しても、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-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)

暗黙メンバ式は、型推論によって暗黙的に型を決定できるコンテキストにおいて、列挙ケースや型メソッドなどの型のメンバにアクセスするための省略記法です。形式は次のとおりです:

暗黙メンバ式

例えば:

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 に変換されます。

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 は無視されています:

(x, _) = (10, 20)
// x は 10 で 20 は 無視されます

GRAMMAR OF A WILDCARD EXPRESSION
wildcard-expression → _

KeyPath 式(Key-Path Expression)

KeyPath 式は、型のプロパティまたはサブスクリプトを参照します。key-value observing などのような、動的プログラミングのタスクで KeyPath 式を使用します。次の形式があります:

Key-Path 式

type name は、String[Int]、や Set<Int> などのジェネリックなパラメータを含めた、具体的な型の名前です。

path は、プロパティ名、サブスクリプト、オプショナルチェーン式、および強制アンラップ式で構成されます。これらの KeyPath コンポーネントのそれぞれは、必要に応じて任意の順序で繰り返すことができます。

コンパイル時には、KeyPath 式は 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 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 型のインスタンスです。例えば:

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-Path String 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 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 は、関数型の任意の式です。

関数定義にパラメータ名が含まれている場合、関数呼び出しは、コロン(:)で区切られた引数値の前に名前を含める必要があります。この種の関数呼び出し式は形式は次のとおりです:

パラメータ名を含んだ関数呼び出し式

関数呼び出し式は、閉じ括弧(})の直後にクロージャ式の形で末尾クロージャを含めることができます。末尾クロージャは、最後の括弧内の引数の後の関数型の引数と解釈されます。最初のクロージャ式に引数ラベルは付けません。次のクロージャ式の前には引数ラベルを付けます。下記の例は、末尾クロージャの構文を使用して、 末尾クロージャを使用しない関数呼び出しバージョンと同等だということを示しています:

// someFunction 関数は引数として整数とクロージャを受け取ります
someFunction(x: x, f: { $0 == 13 })
someFunction(x: x) { $0 == 13 }

// anotherFunction 関数は引数として整数と 2 つのクロージャを受け取ります
anotherFunction(x: x, f: { $0 == 13 }, g: { print(99) })
anotherFunction(x: x) { $0 == 13 } g: { print(99) }

末尾クロージャが関数の唯一の引数の場合は、括弧を省略できます。

// someMethod は唯一の引数としてクロージャを受け取ります
myData.someMethod() { $0 == 13 }
myData.someMethod { $0 == 13 }

引数に末尾クロージャを含めるために、コンパイラは次のように左から右へ関数のパラメータを調べます:

末尾クロージャ パラメータ アクション
ラベルあり ラベルあり ラベルが同じ場合、クロージャはパラメータと一致します。それ以外の場合は、スキップされます
ラベルあり ラベルなし パラメータはスキップされます
ラベルなし ラベルあり/なし 下記に定義されているように、パラメータが関数型と見なされる場合、クロージャはパラメータと一致します。それ以外の場合は、スキップされます。

末尾クロージャは、それが一致する関数のパラメータに渡されます。スキャンプロセス中にスキップされたパラメータには、値が渡されません。例えば、デフォルトのパラメータを使用できます。一致するパラメータを見つけた後、スキャンは次の末尾クロージャと次のパラメータに続きます。マッチングプロセスの最後に、全ての末尾クロージャが一致している必要があります。

構造上、パラメータが in-out パラメータではなく、次のいずれかの場合、パラメータは関数型と見なされます:

  • (Bool) -> Int のようにパラメータの型が関数型
  • @autoclosure () -> ((Bool) -> Int) のように、ラップされた式の型が関数型の自動クロージャパラメータ
  • ((Bool) -> Int)... のように、配列要素の型が関数型の可変長パラメータ
  • Optional<(Bool) -> Int> のように、型がオプショナルの 1 つ以上の層にラップされているパラメータ
  • (Optional<(Bool) -> Int>)... のように、上記の許可された型を組み合わせたパラメータ

末尾クロージャが機能的には関数型のように見えるが関数ではないパラメータと一致する場合、クロージャは必要に応じてラップされます。例えば、パラメータの型がオプショナルの型の場合、クロージャは自動的に Optional でラップされます

これは右から左にマッチングを実行していた Swift 5.3 以前のコードから移行を簡単にするために、スキャン方向で異なる結果を生成する場合は、古い右から左へ順序付けされ、コンパイラは警告を生成します。それ以降の 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()  // - -
someFunction { return $0 + 100 }  // Ambiguous
someFunction { return $0 } secondClosure: { return $0 }  // 10 20

上記の例では、"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 つの関数呼び出しは同等です:

func unsafeFunction(pointer: UnsafePointer<Int>) {
    // ...
}
var myNumber = 1234

unsafeFunction(pointer: &myNumber)
withUnsafePointer(to: myNumber) { unsafeFunction(pointer: $0) }

これらの暗黙の変換によって作成されたポインタは、関数呼び出しの間だけ有効です。未定義の動作を避けるために、関数呼び出しが終了した後までポインタを保持しないようにしてください。

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 trailing-closures
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-closures → closure-expression labeled-trailing-closuresopt
labeled-trailing-closures → labeled-trailing-closure labeled-trailing-closuresopt
labeled-trailing-closure → identifier : closure-expression

イニシャライザ式(Initializer Expression)

イニシャライザ式は型のイニシャライザへアクセスします。形式は次のとおりです:

イニシャライザ式

イニシャライザ式を使用して、型の新しいインスタンスを初期化します。スーパークラスのイニシャライザに委譲するイニシャライザ式を使用することもできます。

class SomeSubClass: SomeSuperClass {
    override init() {
        // subclass の初期化処理をここに
        super.init()
    }
}

関数のように、イニシャライザを値として使用することができます。例えば:

// 型注釈は、String に複数のイニシャイザがあるため必要です
let initializer: (Int) -> String = String.init
let oneTwoThree = [1, 2, 3].map(initializer).reduce("", +)
print(oneTwoThree)
// 123

名前で型を指定した場合は、イニシャライザ式を使用せずに型のイニシャライザにアクセスできます。他の場合では、イニシャライザ式を使用する必要があります。

let s1 = SomeType.init(data: 3)  // 有効
let s2 = SomeType(data: 1)       // これも有効

let s3 = type(of: someValue).init(data: 7)  // 有効
let s4 = type(of: someValue)(data: 5)       // エラー

GRAMMAR OF AN INITIALIZER EXPRESSION
initializer-expression → postfix-expression . init
initializer-expression → postfix-expression . init ( argument-names )

明示的メンバ式(Explicit Member Expression)

明示的メンバ式では、名前付き型、タプル、またはモジュールのメンバへアクセスできます。アイテムとそのメンバの識別子の間のピリオド(.)で構成されています。

明示的メンバ式

名前付き型のメンバは、型の宣言または extension の一部で指定されます。例えば:

class SomeClass {
    var someProperty = 42
}
let c = SomeClass()
let y = c.someProperty  // メンバへのアクセス

タプルのメンバは、0 から始まる整数が順番に暗黙的に指定されており、使用することができます。例えば:

var t = (10, 20, 30)
t.0 = t.1
// t は今 (20, 20, 30)

モジュールのメンバはそのモジュールの最上位の宣言にアクセスします。

dynamicMemberLookup 属性で宣言された型には、Attributes(属性)で説明されているように、実行時に検索できるメンバが含まれています。

パラメータ名だけが異なるメソッドまたはイニシャライザを区別するには、パラメータ名を括弧内に入れ、パラメータ名の後にコロン(:)を書きます。名前のない引数にはアンダースコア(_)を書きます。オーバーロードされたメソッドを区別するには、型注釈を使用してください。例えば:

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              // あいまい
let b = instance.someMethod(x:y:)        // 明確

let d = instance.overloadedMethod        // あいまい
let d = instance.overloadedMethod(x:y:)  // まだあいまい
let d: (Int, Bool) -> Void  = instance.overloadedMethod(x:y:)  // 明確

ピリオドが行の先頭に示されている場合は、暗黙メンバ式としてではなく、明示的メンバ式の一部として解釈されます。例えば、次のリストはメソッドチェーンで呼び出しが複数行にわたって分割された呼び出しを示しています:

let x = [10, 3, 20, 15, 4]
    .sorted()
    .filter { $0 > 5 }
    .map { $0 * 100 }

それぞれのメソッドが呼ばれた時に制御するための条件付きコンパイルブロックを複数行のチェーン構文と組み合わせることもできます。例えば、次のコードは、iOS では異なるフィルタ条件が使用されます:

let numbers = [10, 20, 33, 43, 50]
#if os(iOS)
.filter { $0 < 40 }
#else
.filter { $0 > 25 }
#endif

#if#endif、その他のコンパイルディレクティブの間に、条件付きコンパイルブロックに、暗黙メンバ式とそれに続く 0 個以上の接尾辞を含めて、後置式を形成することができます。また、他の条件付きコンパイルブロック、またはこれらの式とブロックの組み合わせも含めることができます。

この構文は明示的メンバ式を記載できるところんまらどこでも使用可能ですが、トップレベルのコードでは使用できません。

条件付きコンパイルブロックの中では、#if コンパイルディレクティブの条件分岐は、少なくとも 1 つの式を含めなければなりません。その他の分岐は空でも構いません。

GRAMMAR OF AN EXPLICIT MEMBER EXPRESSION
explicit-member-expression → postfix-expression . decimal-digits
explicit-member-expression → postfix-expression . identifier generic-argument-clauseopt
explicit-member-expression → postfix-expression . identifier ( argument-names )
explicit-member-expression → postfix-expression conditional-compilation-block
argument-names → argument-name argument-namesopt
argument-name → identifier :

後置 self 式(Postfix Self Expression)

後置 self 式は、型や式の直後に .self を付けて構成します。次の形式があります:

後置 self 式

最初の形式は expression の値に評価されます。例えば、x.selfx と評価されます。

2 番目の形式は type の値に評価されます。この形式を使用して、型に値としてアクセスできます。例えば、SomeClass.selfSomeClass 型自体に評価されるため、型レベルの引数を受け取る関数またはメソッドに渡すことができます。

GRAMMAR OF A POSTFIX SELF EXPRESSION
postfix-self-expression → postfix-expression . self

サブスクリプト式(Subscript Expression)

サブスクリプト式は、対応するサブスクリプト宣言の get と set を使用してサブスクリプトへのアクセスすることができます。形式は次のとおりです:

subscript式

サブスクリプト式の値を評価するには、expression 型のサブスクリプトの get をサブスクリプトのパラメータとしてインデックス式を渡して呼び出します。値を設定するために、サブスクリプトの set を同じ方法で呼び出します。

サブスクリプト宣言については、Protocol Subscript Declaration(プロトコルサブスクリプト宣言)を参照ください。

GRAMMAR OF A SUBSCRIPT EXPRESSION
subscript-expression → postfix-expression [ function-call-argument-list ]

強制アンラップ式(Forced-Value Expression)

強制アンラップ式は、特定の値が nil ではないオプショナルの値を表します。形式は次のとおりです:

強制アンラップ式

expression の値が nil でない場合、オプショナルの値はアンラップされ、対応するオプショナルの非オプショナルの型で返されます。それ以外の場合は、実行時エラーが発生します。

強制アンラップされた値は、値自体を変化させる、またはその値のメンバの 1 つに割り当てることによって、変更できます。例えば:

var x: Int? = 0
x! += 1
// x は 1

var someDictionary = ["a": [1, 2, 3], "b": [10, 20]]
someDictionary["a"]![0] = 100
// someDictionary は ["a": [100, 2, 3], "b": [10, 20]]

GRAMMAR OF A FORCED-VALUE EXPRESSION
forced-value-expression → postfix-expression !

オプショナルチェーン式(Optional-Chaining Expression)

オプショナルチェーン式は後置式で、オプショナルの値を使用するための簡単な構文を提供します。形式は次のとおりです:

オプショナルチェーン式

後置 ? 演算子は式の値を変更せずに式からオプショナルチェーン式を作成します。

オプショナルチェーン式は、後置式で使用しなければならず、後置式を特別な方法で評価します。オプショナルチェーン式の値が nil の場合、後置式の他の全ての操作は無視され、後置式全体が nil に評価されます。nil ではない場合、値はアンラップされ、後置式の残りの部分を評価するために使用されます。どちらの場合も、後置式の値は依然としてオプショナル型です。

オプショナルチェーン式を含む後置式が他の後置式の内側にネストされている場合は、最も外側の式だけがオプショナル型を返します。下記の例では、cnil ではない場合、その値はアンラップされ、その値は .performAction() を評価するために使用される .property を評価するために使用されます。全体の式 c?.property.performAction() はオプショナルの型の値を持ちます。

var c: SomeClass?
var result: Bool? = c?.property.performAction()

次の例は、オプショナルチェーンを使用せずに上記の例の動作を表現しています。

var result: Bool?
if let unwrappedC = c {
    result = unwrappedC.property.performAction()
}

オプショナルチェーン式のアンラップ値は、その値自体を変える、またはその値のメンバに代入することで変更できます。オプショナルチェーン式の値が nil の場合、代入演算子の右側の式は評価されません。例えば:

func someFunctionWithSideEffects() -> Int {
    return 42  // 実際の副作用はありません
}
var someDictionary = ["a": [1, 2, 3], "b": [10, 20]]

someDictionary["not here"]?[0] = someFunctionWithSideEffects()
// someFunctionWithSideEffects は評価されません
// someDictionary はまだ ["a": [1, 2, 3], "b": [10, 20]]

someDictionary["a"]?[0] = someFunctionWithSideEffects()
// someFunctionWithSideEffects は評価され、42 を返します
// someDictionary は今 ["a": [42, 2, 3], "b": [10, 20]]

GRAMMAR OF AN OPTIONAL-CHAINING EXPRESSION
optional-chaining-expression → postfix-expression ?

results matching ""

    No results matching ""