宣言(Declarations)

最終更新日: 2022/12/3 原文: https://docs.swift.org/swift-book/ReferenceManual/Declarations.html
型、演算子、変数、およびその他の名前と構造を紹介する。
_宣言_はプログラムに新しい名前または構文を導入します。例えば、関数とメソッド、変数と定数の導入や、列挙型、構造体、クラス、およびプロトコルの型の定義のために宣言を使用します。既存の名前付き型の動作を拡張したり、他の場所で宣言されているプログラムにシンボルをインポートするために宣言を使用できます。
Swift では、ほとんどの宣言は、宣言されているのと同時に実装または初期化されているという点で定義と同等です。一方で、プロトコルはメンバを実装していないため、ほとんどのプロトコルメンバは宣言だけです。便宜上、この区別は重要ではないため、_宣言_という用語は宣言と定義の両方をカバーします。
GRAMMAR OF A DECLARATION declaration → import-declaration declaration → constant-declaration declaration → variable-declaration declaration → typealias-declaration declaration → function-declaration declaration → enum-declaration declaration → struct-declaration declaration → class-declaration declaration → protocol-declaration declaration → initializer-declaration declaration → deinitializer-declaration declaration → extension-declaration declaration → subscript-declaration declaration → operator-declaration declaration → precedence-group-declaration declarations → declaration declarationsopt

トップレベルコード(Top-Level Code)

Swift ソースファイルのトップレベルコードは、0 個以上の文、宣言、式で構成されています。デフォルトでは、ソースファイルのトップレベルで宣言されている変数、定数、およびその他の名前付き宣言は、同じモジュールの全てのソースファイル内のコードからアクセスできます。Access Control Levels(アクセス制御レベル)で説明されているように、宣言をアクセスレベル修飾子でマークすることで、このデフォルトの動作をオーバーライドできます。
トップレベルコードには 2 種類あります: トップレベル宣言と実行可能トップレベルコードです。トップレベル宣言は宣言のみで構成され、全ての Swift ソースファイルで許可されています。実行可能トップレベルコードには、宣言だけでなく、文と式が含まれており、プログラムのトップレベルのエントリポイントとしてのみ使用できます。
コードがファイルやモジュールに構成されている方法に関係なく、実行可能にするためにコンパイルした Swift のコードは、トップレベルのエントリポイントをマークする次の方法の内の 1 つを含めることができます: main 属性、NSApplicationMain 属性、UIApplicationMain 属性、main.swift ファイル、またはトップレベルの実行可能コードを含むファイルです。
GRAMMAR OF A TOP-LEVEL DECLARATION top-level-declaration → statementsopt

コードブロック(Code Blocks)

_コードブロック_は、文をグループ化するための様々な宣言および制御構造によって使用されます。形式は次のとおりです:
コードブロック
コードブロック内の statements には、宣言、式、およびその他の文が含まれており、ソースコード内の出現順に実行されます。
GRAMMAR OF A CODE BLOCK code-block → { statementsopt }

インポート宣言(Import Declaration)

_インポート宣言_を使用すると、現在のファイルの外部で宣言されているシンボルにアクセスできます。基本形式はモジュール全体をインポートします。import キーワードとそれに続くモジュール名で構成されます:
インポート宣言
シンボルのインポートをより細かく制限するために、インポート宣言には、モジュールまたはサブモジュール内で特定のサブモジュールまたは宣言を指定できます。この詳細な形式を使用する場合は、(それを宣言するモジュールではなく)インポートされたシンボルだけが現在のスコープで利用可能になります。
シンボルのインポート宣言
GRAMMAR OF AN IMPORT DECLARATION import-declaration → attributesopt import import-kindopt import-path import-kind → typealias | struct | class | enum | protocol | let | var | func import-path → import-path-identifier | import-path-identifier . import-path import-path-identifier → identifier | operator

定数宣言(Constant Declaration)

_定数宣言_では、プログラムに名前付きの定数値を導入します。定数宣言は let キーワードを使用して宣言され、形式は次のとおりです。
Constant Declaration(定数宣言)
定数宣言は、constant name と値を初期化する expression の間の不変の繋がりを定義します。定数の値は設定されたら変更できません。つまり、定数がクラスオブジェクトで初期化されている場合、オブジェクト自体を変更できますが、定数名とそれが参照するオブジェクトの間の繋がりは変更できません。
定数がグローバルスコープで宣言されている場合は、値を使って初期化する必要があります。関数またはメソッドのコンテキストに定数宣言があると、その値が初めて読み込まれる前に値が設定されることが確実な限り、後で初期化できます。コンパイラが定数の値が読み取られないことをわかっている場合、定数に値を絶対に設定する必要はありません。クラスまたは構造体宣言のコンテキストでの定数宣言は、_定数プロパティ_と見なされます。定数宣言は計算プロパティではないため、get または set を持ちません。
定数宣言の constant name がタプルの場合、タプル内の各項目の名前は、値を初期化する expression を通して対応する値にバインドされます。
let (firstNumber, secondNumber) = (10, 42)
この例では、firstNumber は値 10 の名前付き定数で、secondNumber42 の名前付き定数です。両方の定数は独立して使用できます。
print("The first number is \(firstNumber).")
// The first number is 10.
print("The second number is \(secondNumber).")
// The second number is 42.
型注釈(:type)は、Type Inference(型推論)で説明されているように、constant name の型を推論できる場合は、省略可能です。
定数型プロパティを宣言するには、宣言に static 修飾子をマークします。クラスの定数型プロパティは常に暗黙的に final です。サブクラスによるオーバーライドを許可または禁止するために、class または final 修飾子をマークすることはできません。型プロパティは、Type Properties(型プロパティ)で説明されています。
定数の詳細およびそれらを使用するときのガイダンスについては、Constants and Variables(定数と変数)Stored Properties(格納プロパティ)を参照ください。
GRAMMAR OF A CONSTANT DECLARATION constant-declaration → attributesopt declaration-modifiersopt let pattern-initializer-list pattern-initializer-list → pattern-initializer | pattern-initializer , pattern-initializer-list pattern-initializer → pattern initializeropt initializer → = expression

変数宣言(Variable Declaration)

_変数宣言_では、プログラムに名前付きの変数値を導入し、var キーワードを使用して宣言されます。
変数宣言には、格納/計算変数や格納/計算プロパティ、格納変数オブザーバやプロパティオブザーバ、および静的変数プロパティなど、様々な種類の名前付きで可変な値を宣言する形式があります。適切な形式は、変数が宣言されているスコープと宣言する変数の種類によって異なります。
NOTE Protocol Property Declaration(プロトコルプロパティ宣言)で説明されているように、プロトコル宣言のコンテキストでプロパティを宣言することもできます。
Overriding(オーバーライド)で説明されているように、サブクラスのプロパティ宣言に override 修飾子をマークすることで、サブクラス内でプロパティをオーバーライドできます。

格納変数、格納可変プロパティ(Stored Variables and Stored Variable Properties)

次の形式は、格納変数や格納可変プロパティを宣言します。
格納変数、格納可変プロパティ
この形式の変数宣言は、グローバルスコープ、関数のローカルスコープ、またはクラスまたは構造体宣言のコンテキストで定義できます。この形式の変数宣言が、グローバルスコープまたは関数のローカルスコープで宣言されている場合は、_格納変数_と呼ばれます。クラスまたは構造体宣言のコンテキストで宣言されている場合は、_格納可変プロパティ_と呼ばれます。
値を初期化する expression はプロトコル宣言に定義できませんが、他の全てのコンテキストで、値を初期化する expression は任意で可能す。つまり、値を初期化する expression が存在しない場合、変数宣言に明示的な型注釈(: type)を含める必要があります。
定数宣言と同様に、variable name がタプルの場合、タプル内の各項目の名前は、値を初期化する expression の対応する値にバインドされます。
それらの名前が示唆するように、格納変数または格納可変プロパティの値がメモリに格納されます。

計算変数、計算変数プロパティ(Computed Variables and Computed Properties)

次の形式は、計算変数または計算プロパティを宣言します。
計算変数、計算変数プロパティ
この形式の変数宣言は、グローバルスコープ、関数のローカルスコープ、またはクラス、構造体、列挙型、または extension のコンテキストで定義できます。この形式の変数宣言がグローバルスコープまたは関数のローカルスコープで宣言されている場合は、_計算変数_と呼ばれます。クラス、構造体、または extension のコンテキストで宣言されている場合は、それは_計算プロパティ_と呼ばれます。
get は値を読み取るために使用され、set は値を書き込むために使用されます。set 句は省略可能で、get のみが必要な場合は、Read-Only Computed Properties(読み取り専用計算プロパティ)で説明されているように、両方の句を省略し、シンプルに要求された値を直接返すことができます。しかし、set 句を指定した場合は、get 句も提供する必要があります。
setter name とそれを囲む括弧は省略可能です。setter name を指定した場合は、set のパラメータ名として使用されます。setter name を指定しない場合は、Shorthand Setter Declaration(省略 set プロパティ宣言)で説明されているように、set へのデフォルトのパラメータ名は newValue です。
格納変数や格納可変プロパティとは異なり、計算変数または計算プロパティの値はメモリに格納されません。
詳細や計算プロパティの例は、Computed Properties(計算プロパティ)を参照ください。

格納変数オブザーバとプロパティオブザーバ(Stored Variable Observers and Property Observers)

格納変数またはプロパティを willSetdidSet オブザーバと一緒に宣言することもできます。オブザーバで宣言された格納変数またはプロパティの形式は次のとおりです:
格納変数オブザーバとプロパティオブザーバ
この形式の変数宣言は、グローバルスコープ、関数のローカルスコープ、またはクラスまたは構造体宣言のコンテキストで定義できます。この形式の変数宣言がグローバルスコープまたは関数のローカルスコープで宣言されている場合、オブザーバは_格納変数オブザーバ_と呼ばれます。クラスまたは構造体宣言のコンテキストで宣言されている場合、オブザーバは_プロパティオブザーバ_と呼ばれます。
任意の格納プロパティにプロパティオブザーバを追加できます。Overriding Property Observers(プロパティオブザーバのオーバーライド)で説明されているように、サブクラス内でプロパティをオーバーライドすることで、継承したプロパティ(格納または計算プロパティ)にプロパティオブサーバを追加することもできます。
値を初期化する expression は、クラスまたは構造体宣言のコンテキストでは省略可能ですが、他の場所では必須です。_型注釈_は、型が値を初期化する expression から推論できる場合は省略可能です。この式は、プロパティの値が初めて読まれるときに評価されます。プロパティの値を読み込む前にプロパティの初期値を上書きする場合、この式はプロパティに初めて書き込まれる前に評価されます。
willSet および didSet オブザーバは、変数またはプロパティの値が設定されるときに、その値を監視(そして適切に対応する)方法を提供します。変数またはプロパティが最初に初期化される場合は、オブザーバは呼び出されません。代わりに、それらは初期化以外で値が設定されている場合にのみ呼び出されます。
willSet オブザーバは、変数またはプロパティの値が設定される直前に呼び出されます。新しい値が定数として willSet オブザーバに渡されるため、 willSet 句の実装では変更できません。didSet オブザーバは、新しい値が設定された直後に呼び出されます。willSet オブザーバとは対照的に、それにアクセスする必要がある場合は、変数またはプロパティの古い値が didSet オブザーバーに渡されます。つまり、自身の didSet オブザーバ句内で変数またはプロパティに値を割り当てた場合、直前で設定して willSet オブザーバに渡された値を置き換えます。
willSet および didSet 句内の setter name とそれを囲む括弧は省略可能です。setter name を指定した場合は、willSetdidSet オブザーバのパラメータ名として使用されます。setter name を指定しない場合は、willSet オブザーバのデフォルトのパラメータ名が newValue で、didSet オブザーバのデフォルトのパラメータ名は oldValue です。
didSet 句は、willSet 句を指定した場合は省略可能です。同様に、didSet 句を指定するときは、willSet 句は省略可能です。
didSet オブザーバの本文が古い値を参照する場合、get はオブザーバの前に呼び出され、古い値を使用できます。それ以外の場合は、スーパークラスの get を呼び出さずに新しい値が格納されます。下記の例は、スーパークラスで定義され、オブザーバを追加するためにそのサブクラスでオーバーライドされた計算プロパティを示しています:
class Superclass {
private var xValue = 12
var x: Int {
get { print("Getter was called"); return xValue }
set { print("Setter was called"); xValue = newValue }
}
}
// このサブクラスは オブザーバ の oldValue を参照していません
// SuperClass の get は、値を出力するために一度だけ呼び出されます。
class New: Superclass {
override var x: Int {
didSet { print("New value \(x)") }
}
}
let new = New()
new.x = 100
// Setter was called
// Getter was called
// New value 100
// このサブクラスはそのオブザーバの oldValue を参照しているので、スーパークラスの
// get はセッターの前に一度呼び出され、また値を出力します
class NewAndOld: Superclass {
override var x: Int {
didSet { print("Old value \(oldValue) - new value \(x)") }
}
}
let newAndOld = NewAndOld()
newAndOld.x = 200
// Getter was called
// Setter was called
// Getter was called
// Old value 12 - new value 200
より詳細な情報やプロパティオブザーバの使用方法の例は、Property Observers(プロパティオブザーバ)を参照ください。

型変数プロパティ(Type Variable Properties)

型変数プロパティを宣言するには、宣言を static 修飾子でマークします。サブクラスがスーパークラスの実装をオーバーライドできるようにするには、代わりに class 修飾子を使用して型計算プロパティを宣言することができます。型プロパティは、Type Properties(型プロパティ)で説明されています。
GRAMMAR OF A VARIABLE DECLARATION variable-declaration → variable-declaration-head pattern-initializer-list variable-declaration → variable-declaration-head variable-name type-annotation code-block variable-declaration → variable-declaration-head variable-name type-annotation getter-setter-block variable-declaration → variable-declaration-head variable-name type-annotation getter-setter-keyword-block variable-declaration → variable-declaration-head variable-name initializer willSet-didSet-block variable-declaration → variable-declaration-head variable-name type-annotation initializeropt willSet-didSet-block variable-declaration-head → attributesopt declaration-modifiersopt var variable-name → identifier getter-setter-block → code-block getter-setter-block → { getter-clause setter-clauseopt } getter-setter-block → { setter-clause getter-clause } getter-clause → attributesopt mutation-modifieropt get code-block setter-clause → attributesopt mutation-modifieropt set setter-nameopt code-block setter-name → ( identifier ) getter-setter-keyword-block → { getter-keyword-clause setter-keyword-clauseopt } getter-setter-keyword-block → { setter-keyword-clause getter-keyword-clause } getter-keyword-clause → attributesopt mutation-modifieropt get setter-keyword-clause → attributesopt mutation-modifieropt set willSet-didSet-block → { willSet-clause didSet-clauseopt } willSet-didSet-block → { didSet-clause willSet-clauseopt } willSet-clause → attributesopt willSet setter-nameopt code-block didSet-clause → attributesopt didSet setter-nameopt code-block

タイプエイリアス宣言(Type Alias Declaration)

_タイプエイリアス宣言_では、既存の型に別名を導入します。タイプエイリアス宣言は、typealias キーワードを使用して宣言され、形式は次のとおりです:
タイプエイリアス宣言
タイプエイリアスが宣言された後、プログラム内の既存の型の代わりに注釈された name を使用できます。existing type は、名前付き型または複合型にすることができます。タイプエイリアスは新しい型を作成しません。それらは単に名前が既存の型を参照することを可能にします。
タイプエイリアス宣言は、ジェネリックパラメータを使用して既存のジェネリック型に名前を付けることができます。そのタイプエイリアスは、既存の型のジェネリックパラメータの一部または全部を使って具象型を提供できます。例えば:
typealias StringDictionary<Value> = Dictionary<String, Value>
// 以下の辞書は同じ型を持っています
var dictionary1: StringDictionary<Int> = [:]
var dictionary2: Dictionary<String, Int> = [:]
タイプエイリアスがジェネリックパラメータで宣言されると、それらのパラメータの制約は既存の型のジェネリックパラメータの制約と正確に一致する必要があります。例えば:
typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>
タイプエイリアスと既存の型は互換的に使用される可能性があるため、タイプエイリアスは追加のジェネリック制約を導入できません。
タイプエイリアスは、宣言から全てのジェネリックパラメータを省略することで、既存の型のジェネリックパラメータを流用できます。例えば、ここで宣言されている Diccionario というタイプエイリアスは、Dictionary と同じジェネリックパラメータと制約を持ちます。
typealias Diccionario = Dictionary
プロトコル宣言の内部では、タイプエイリアスは頻繁に使用される型に短くて便利な名前を付けることができます。例えば:
protocol Sequence {
associatedtype Iterator: IteratorProtocol
typealias Element = Iterator.Element
}
func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
// ...
}
このタイプエイリアスがないと、sum 関数は関連型を T.Element ではなく T.Iterator.Element として参照する必要があります。
GRAMMAR OF A TYPE ALIAS DECLARATION typealias-declaration → attributesopt access-level-modifieropt typealias typealias-name generic-parameter-clauseopt typealias-assignment typealias-name → identifier typealias-assignment → = type

関数宣言(Function Declaration)

_関数宣言_では、プログラムに関数またはメソッドを導入します。クラス、構造体、列挙型、またはプロトコルのコンテキストで宣言されている関数は_メソッド_と呼ばれます。関数宣言は func キーワードを使用して宣言され、形式は次のとおりです:
関数宣言
関数の戻り値の型が Void の場合は、次のように戻り値の型を省略できます:
関数宣言戻り値の型Void
各パラメータには型を含める必要があります。推論することはできません。パラメータ型の前に inout を書くと、その関数の範囲内でパラメータを変更できます。in-out パラメータについては、下記のIn-Out Parameters(In-Out パラメータ)で詳細に説明されています。
statements が単一式のみを含む関数宣言は、その式の値を返すことが明らかです。この暗黙的なリターン構文は、式の型と関数の戻り値の型が Void やケースを持たない Never のような列挙型ではない場合にのみ使用できます。
関数は、戻り値の型としてタプル型を使用して複数の値を返すことができます。
関数定義は他の関数宣言の内部に現れることがあります。この種の関数は_ネスト関数_と呼ばれます。
ネスト関数は、in-out パラメータのように決してエスケープしないことが確実な値をキャプチャしている場合、または非エスケープ関数の引数として渡される場合は、非エスケープです。それ以外の場合、ネスト関数はエスケープ関数です。
ネスト関数については、を参照ください。

Parameter Names(パラメータ名)

関数パラメータは、各パラメータが複数の形式のうちの 1 つを持つカンマ区切りのリストです。関数呼び出し内の引数の順序は、関数の宣言内のパラメータの順序と一致する必要があります。パラメータリスト内の最もシンプルなエントリの形式は次のとおりです:
パラメータリスト内の最もシンプルなエントリ
パラメータには、関数本文内で使用されている名前、および関数またはメソッドを呼び出すときに使用される引数ラベルがあります。デフォルトでは、パラメータ名は引数ラベルとしても使用されます。例えば:
func f(x: Int, y: Int) -> Int { return x + y }
f(x: 1, y: 2) // x と y の両方にラベルがあります
次のいずれかの形式で、引数ラベルのデフォルトの動作を上書きできます。
引数ラベルのデフォルトの動作を上書き
パラメータ名の前の名前は、パラメータの明示的な引数ラベルで、パラメータ名とは異なる可能性があります。関数呼び出しまたはメソッド呼び出し時は、対応する引数に指定された引数ラベルを使用する必要があります。
パラメータ名の前にアンダースコア(_)を付けると、引数ラベルが省略されます。関数呼び出しまたはメソッド呼び出し時は、対応する引数に、ラベルを付けてはなりません。
func repeatGreeting(_ greeting: String, count n: Int) { /* n 回あいさつ */ }
repeatGreeting("Hello, world!", count: 2) // count は ラベルあち, greeting は ラベルなし

In-Out パラメータ(In-Out Parameters)

in-out パラメータは次のように渡されます:
  1. 1.
    関数が呼び出されると、引数の値がコピーされます
  2. 2.
    関数の本文では、コピーが変更されます
  3. 3.
    関数から戻ると、コピーの値が元の引数に割り当てられます
この動作は_コピーインコピーアウト_または_値渡し_と呼ばれます。例えば、計算プロパティまたはオブザーバを持つプロパティが in-out パラメータとして渡されると、その get は関数呼び出しの一部として呼び出され、その set は関数リターンの一部として呼び出されます。
最適化として、引数がメモリ内の物理アドレスに格納されている値の場合、関数本文の内側と外側の両方で同じメモリアドレスが使用されます。最適化された動作は、_参照渡し_と呼ばれます。これはコピーのオーバーヘッドを削減しながら、コピーインコピーアウトモデルの全ての要件を満たします。参照渡しに依存せず、コピーインコピーアウトで与えられたモデルを使用してコードを書きましょう。そうすれば、最適化の有無にかかわらず正しく動作します。
関数内で、元の値が現在のスコープで使用可能でも、in-out 引数として渡された値にアクセスしないでください。元の値へのアクセスは、Swift のメモリ排他性に対する保証に違反した値への同時アクセスです。同じ理由で、同じ値を複数の in-out パラメータに渡すことはできません。
メモリの安全性とメモリの排他性の詳細については、Memory Safety(メモリ安全性)を参照ください。
in-out パラメータをキャプチャするクロージャまたはネスト関数は、非エスケープでなければなりません。in-out パラメータを変えることなくキャプチャする必要がある場合は、キャプチャリストを使用して、パラメータを不変なものとして明示的にキャプチャします。
func someFunction(a: inout Int) -> () -> Int {
return { [a] in return a + 1 }
}
in-out パラメータをキャプチャして変更する必要がある場合は、マルチスレッドコードで関数が返される前に全ての変更が終了することを保証するように、明示的にローカルコピーを使用してください。
func multithreadedFunction(queue: DispatchQueue, x: inout Int) {
// 手動でローカルコピーを作成します
var localX = x
defer { x = localX }
// localXを非同期的に操作してから、戻る前に待機します
queue.async { someMutatingOperation(&localX) }
queue.sync {}
}
より多くの議論と in-out パラメータの例については、In-Out Parameters(In-Out パラメータ)を参照ください。

特殊な種類のパラメータ(Special Kinds of Parameters)

パラメータを無視したり、1 つのパラメータに複数の値を受け取ったり、デフォルト値を提供できます。形式は次のとおりです:
特殊な種類のパラメータ
アンダースコア(_)パラメータは明示的に無視され、関数の本文内でアクセスすることはできません。
型名の直後に 3 つのドット(...)を続くパラメータは、可変長パラメータとして解釈されます。可変長パラメータのすぐ後に続くパラメータには、引数ラベルが必要です。関数は複数の可変長パラメータを持つことができます。可変長パラメータは、型名の要素の配列として扱われます。例えば、可変長パラメータ Int...[Int] として扱われます。可変長パラメータを使用する例については、Variadic Parameters(可変長パラメータ)を参照ください。
等式(=)パラメータと型の後に式を伴うパラメータは、指定された式をデフォルト値として解釈します。指定された式は、関数が呼び出された時に評価されます。関数呼び出し時にパラメータを省略すると、デフォルト値が代わりに使用されます。
func f(x: Int = 42) -> Int { return x }
f() // 有効。デフォルト値を使用します
f(x: 7) // 有効。提供された値を使用します
f(7) // 無効。引数ラベルがありません

特殊な種類のメソッド(Special Kinds of Methods)

self を変更する列挙型または構造体のメソッドは、mutating 修飾子でマークされていなければなりません。
スーパークラスメソッドをオーバーライドするメソッドは、override 修飾子でマークされている必要があります。これは、override 修飾子なしでメソッドをオーバーライド、逆にスーパークラスメソッドをオーバーライドしないメソッドで override 修飾子を使用するとコンパイルエラーになります。
型のインスタンスではなく型自体に紐づくメソッドは、列挙型および構造体の static 修飾子、またはクラスの static または class 修飾子のいずれかでマークされている必要があります。class 修飾子でマークされたクラス型メソッドは、サブクラスでオーバーライドできます。class final または static でマークされたクラス型メソッドはオーバーライドできません。

特別な名前のメソッド(Methods with Special Names)

いくつかの特別な名前のメソッドは、関数呼び出しの糖衣構文(シンタックスシュガー)を使用できます。ある型がこれらのメソッドの内の 1 つを定義している場合、そのインスタンスを関数呼び出し構文で使用できます。それは、そのインスタンス上の特別な名前のメソッドの呼び出しだと解釈されます。
クラス、構造体、または列挙型は、dynamicCallableで説明されているように、dynamicallyCall(withArguments:) メソッドまたは dynamicallyCall(withKeywordArguments:) メソッドを定義することによって、または下記で説明されているように、call-as-function メソッドを定義することによって、関数呼び出し構文をサポートできます。型が call-as-function メソッドと dynamicCallable 属性のメソッドの両方を定義している場合、コンパイラはどちらの方法も使用できる状況では、call-as-function メソッドを選びます。
call-as-function メソッドの名前は、callAsFunction()、または callAsFunction( で始まり、ラベル有りまたはなしの引数を付けた別の名前(例えば、callAsFunction(_:_:)callAsFunction(something:) も有効です。
次の関数呼び出しは同等です:
struct CallableStruct {
var value: Int
func callAsFunction(_ number: Int, scale: Int) {
print(scale * (number + value))
}
}
let callable = CallableStruct(value: 100)
callable(4, scale: 2)
callable.callAsFunction(4, scale: 2)
// 両方の関数は印刷 208 を出力します
call-as-function メソッドと dynamicCallable 属性のメソッドは、型システムにどのくらいの情報を与え、実行時にどのくらい動的な動作が可能かの間で異なるトレードオフがあります。call-as-function メソッドを宣言すると、引数の数、および各引数の型とラベルを指定します。dynamicCallable 属性のメソッドは、引数の配列を保持するために使用される型のみを指定できます。
call-as-function メソッド、または dynamicCallable 属性のメソッドを定義することは、任意のコンテキスト内で関数呼び出し以外の関数のようにその型のインスタンスを使用してはいけません。例えば:
let someFunction1: (Int, Int) -> Void = callable(_:scale:) // エラー
let someFunction2: (Int, Int) -> Void = callable.callAsFunction(_:scale:)
subscript(dynamicMember:) は、dynamicMemberLookupで説明されているように、メンバを検索するための糖衣構文(シンタックスシュガー)です。

スロー関数とスローメソッド(Throwing Functions and Methods)

スロー関数とスローメソッドは、throws キーワードでマークされている必要があります。これらの関数およびメソッドは、_スロー関数_および_スローメソッド_と呼ばれます。形式は次のとおりです:
スロー関数とスローメソッド
スロー関数またはスローメソッドの呼び出しは、try または try! 式で囲まれていなければなりません(つまり、try または try! 演算子のスコープ内)。
throws キーワードは関数の型の一部で、非スロー関数はスロー関数のサブタイプです。その結果、スロー関数が期待されているコンテキストで非スロー関数を使用することができます。
関数がエラーをスローできるかどうかだけを基に、関数をオーバーロードすることはできません。一方で、関数の parameter がエラーをスローできるかどうかに基づいて関数をオーバーロードすることができます。
スローメソッドは、非スローメソッドをオーバーライドすることができず、非スローメソッドのプロトコル要件を満たすことができません。逆に、非スローメソッドはスローメソッドをオーバーライドすることができ、スローメソッドのプロトコル要件を満たすことができます。

再スロー関数と再スローメソッド(Rethrowing Functions and Methods)

関数またはメソッドが、そのパラメータの 1 つがエラーをスローした場合にのみエラーをスローすることを示すために rethrows キーワードを使うことができます。これらの関数およびメソッドは、_再スロー関数_および_再スローメソッド_と呼ばれます。再スロー関数と再スローメソッドには、少なくとも 1 つのエラーをスローする関数のパラメータが必要です。
func someFunction(callback: () throws -> Void) rethrows {
try callback()
}
再スロー関数または再スローメソッドには、catch 句内でのみ throw 文を含めることができます。これにより、do-catch 文内でスロー関数を呼び出し、catch 句で別のエラーを投げてエラーを処理できます。さらに、catch 句は、再スロー関数のスローパラメータの 1 つからスローされたエラーのみを処理しなければなりません。例えば、次の例では、catch 句は alwaysthrows() からスローされたエラーを処理しているため、無効です:
func alwaysThrows() throws {
throw SomeError.error
}
func someFunction(callback: () throws -> Void) rethrows {
do {
try callback()
try alwaysThrows() // alwaysThrows() はスローパラメータではないため無効です。
} catch {
throw AnotherError.error
}
}
スローメソッドは再スローメソッドをオーバーライドできず、再スローメソッドのプロトコル要件を満たすことができません。逆に、再スローメソッドはスローメソッドをオーバーライドでき、再スローメソッドはスローメソッドのプロトコル要件を満たすことができます。

非同期関数と非同期メソッド(Asynchronous Functions and Methods)

非同期に実行される関数とメソッドは、async キーワードでマークされている必要があります。これらの関数とメソッドは、_非同期関数_と_非同期メソッド_と呼ばれています。形式は次のとおりです:
非同期関数と非同期メソッド
非同期関数または非同期メソッドの呼び出しは、await でラップされていなければなりません。
async キーワードは関数の型の一部で、同期関数は非同期関数のサブタイプのため、非同期関数が期待されるコンテキストで同期関数を使用できます。例えば、同期メソッドを使用して非同期メソッドをオーバーライドでき、同期メソッドは非同期メソッドのプロトコル要件を満たすことができます。

ノーリターン関数(Functions that Never Return)

Swift は、関数またはメソッドがその呼び出し元に戻り値を返さないことを示す Never を定義しています。戻り値のない型を持つ関数とメソッドは、_ノーリターン_と呼ばれます。ノーリターン関数とノーリターンメソッドは、回復不能なエラーを引き起こすか、または無期限に続く一連のタスクを始めます。つまり、呼び出すとそれ以降のコードが決して実行されないことを意味します。スロー関数や再スロー関数では、ノーリターンでも、適切な catch 句を使ってプログラムの制御を転送できます。
Guard Statement(Guard 文)で説明したように、ノーリターン関数またはノーリターンメソッドは guard 文の else 句を終わらせるために呼び出すことができます。
ノーリターンメソッドはオーバーライドできますが、その新しいメソッドは戻り値の型とノーリターンの動作を保ち続ける必要があります。
GRAMMAR OF A FUNCTION DECLARATION function-declaration → function-head function-name generic-parameter-clauseopt function-signaturegeneric-where-clauseopt function-bodyopt function-head → attributesopt declaration-modifiersopt func function-name → identifier | operator function-signature → parameter-clause asyncopt throwsopt function-resultopt function-signature → parameter-clause asyncopt rethrows function-resultopt function-result → -> attributesopt type function-body → code-block parameter-clause → ( ) | ( parameter-list ) parameter-list → parameter | parameter , parameter-list parameter → external-parameter-nameopt local-parameter-name type-annotation default-argument-clauseopt parameter → external-parameter-nameopt local-parameter-name type-annotation parameter → external-parameter-nameopt local-parameter-name type-annotation ... external-parameter-name → identifier local-parameter-name → identifier default-argument-clause → = expression

列挙型宣言(Enumeration Declaration)

_列挙型宣言_は、名前付きの列挙型をプログラムに導入します。
列挙型宣言には 2 つの基本的な形式があり、enum キーワードを使用して宣言されます。いずれかの形式を使用して宣言された列挙型の本文には、_列挙ケース_と呼ばれる 0 個以上の値と、計算プロパティ、インスタンスメソッド、型メソッド、イニシャライザ、タイプエイリアス、さらには他の列挙型、構造体、クラス、アクター宣言を含めることができます。列挙型宣言には、デイニシャライザまたはプロトコル宣言を含めることはできません。
列挙型は任意の数のプロトコルに準拠できますが、クラス、構造体、またはその他の列挙型を継承することはできません。
クラスや構造体とは異なり、列挙型には暗黙的に提供されるデフォルトのイニシャライザがありません。全てのイニシャライザを明示的に宣言する必要があります。イニシャライザは、列挙型内の他のイニシャライザに委譲できますが、初期化プロセスは、イニシャライザが列挙ケースの 1 つを自分自身に割り当てた後にのみ完了します。
構造体と似ていますが、クラスとは異なり、列挙型は値型です。列挙型のインスタンスは、変数または定数に割り当てられたとき、または引数として関数呼び出し時に渡されたときにコピーされます。値型の詳細については、Structures and Enumerations Are Value Types(構造体と列挙型は値型)を参照ください。
Extension Declaration(拡張宣言)で説明されているように、extension を使用して列挙型の動作を拡張できます。

任意の型のケースを持つ列挙型(Enumerations with Cases of Any Type)

次の形式は、任意の型のケースを含む列挙型を宣言しています。
任意の型のケースを持つ列挙型
この形式で宣言された列挙型は、他のプログラミング言語では判別共用体(discriminated union)と呼ばれることもあります。
この形式では、各ケースブロックは、case キーワードと、それに続く 1 つ以上の列挙ケースで構成され、カンマ(,)で区切られます。各ケースの名前は一意にする必要があります。各ケースでは、特定の型の値を格納するように指定することもできます。これらの型は、ケースの名前の直後にある、関連値 のタプルで指定できます。
関連値を持つ列挙ケースは、指定された関連値を使用して列挙型のインスタンスを作成する関数として使用できます。また、関数と同様に、列挙ケースへの参照を取得して、後のコードで使用できます。
enum Number {
case integer(Int)
case real(Double)
}
let f = Number.integer
// f は (Int) -> Number 型の関数です
// f を適用して、整数値を持つ Number インスタンスの配列を作成します
let evenInts: [Number] = [0, 2, 4, 6].map(f)
詳細および関連値型を持つケースの例については、Associated Values(関連値)を参照ください。

再帰列挙型(Enumerations with Indirection)

列挙型は再帰的な構造を持つことができます。つまり、列挙型自体のインスタンスの値をケースの関連値として持つことができます。ただし、列挙型のインスタンスは値型のセマンティクスです。つまり、不変のメモリレイアウトを持っています。再帰をサポートするには、コンパイラが間接層を挿入する必要があります。
特定の列挙ケースの間接層を挿入するには、indirect 修飾子でマークします。indirect ケースには、関連値が必要です。
enum Tree<T> {
case empty
indirect case node(value: T, left: Tree, right: Tree)
}
関連値を持つ列挙型の全てのケースで indirect を有効にするには、列挙型全体に indirect 修飾子を付けます。これは、列挙型を indirect 修飾子でマークする必要があるケースが多く含まれている場合に便利です。
indirect 修飾子でマークされた列挙型には、関連値を持つケースと関連値を持たないケースが混在している可能性があります。しかし、ケースに indirect 修飾子を付けることはできません。

Raw Value 型のケースを持つ列挙型(Enumerations with Cases of a Raw-Value Type)

次の形式は、同じ基となる型のケースを持つ列挙型を宣言しています。
Raw Value型のケースを持つ列挙型
この形式では、各ケースブロックは、case キーワードと、それに続く 1 つ以上の列挙ケースで構成され、カンマ(,)で区切られます。最初の形式のケースとは異なり、各ケースには、同じ基本型の Raw Value と呼ばれる基になる値があります。これらの値の型は Raw Value 型 で指定され、整数、浮動小数点数、文字列、または単一文字の必要があります。特に、Raw Value 型は、Equatable プロトコルおよび次のいずれかのプロトコルに準拠する必要があります: 整数リテラルの場合は ExpressibleByIntegerLiteral、浮動小数点リテラルの場合は ExpressibleByFloatLiteral、任意の数の文字を含む文字列リテラルの場合は ExpressibleByStringLiteral、文字列の場合は ExpressibleByUnicodeScalarLiteral、1 文字のみを含むリテラルの場合は ExpressibleByExtendedGraphemeClusterLiteral です。各ケースには一意の名前と一意の Raw Value が割り当てられている必要があります。
Raw Value 型に Int が指定されているものの、ケースに値が割り当てられていない場合、012 などの値が暗黙的に割り当てられます。値が割り当てられていない各ケースには、前のケースの Raw Value から自動的にインクリメントされた Raw Value が暗黙的に割り当てられます。
enum ExampleEnum: Int {
case a, b, c = 5, d
}
上記の例では、ExampleEnum.a の Raw Value は 0 で、ExampleEnum.b1 です。また、ExampleEnum.c の値は明示的に 5 に設定されているため、ExampleEnum.d の値は自動的に 5 からインクリメントされます。したがって、6 です。
Raw Value 型が文字列として指定されていて、ケースに値が明示的に割り当てない場合、割り当てられていない各ケースには、そのケースの名前と同じテキストの文字列が暗黙的に割り当てられます。
enum GamePlayMode: String {
case cooperative, individual, competitive
}
上記の例では、GamePlayMode.cooperative の Raw Value は "cooperative"GamePlayMode.individual の Raw Value は "individual"GamePlayMode.competitive の Raw Value は "competitive" です。
Raw Value 型のケースを持つ列挙型は、Swift 標準ライブラリで定義されている RawRepresentable プロトコルに暗黙的に準拠しています。その結果、rawValue プロパティと、失敗可能イニシャライザ init?(rawValue: RawValue) を持ちます。ExampleEnum.b.rawValue のように、rawValue プロパティを使用して、列挙型の Raw Value にアクセスできます。また、ExampleEnum(rawValue: 5) のように、失敗可能イニシャライザを呼び出すことにより、Raw Value を使用して対応するケースを探すことができます。オプショナルの列挙ケースを返します。詳細および Raw Value 型のケースの例については、Raw Valuesを参照ください。

列挙ケースへのアクセス(Accessing Enumeration Cases)

列挙ケースを参照するには、EnumerationType.enumerationCase と同様に、ドット(.)構文を使用します。列挙の型を推論できる場合は、Enumeration Syntax(列挙型構文)Implicit Member Expression(暗黙メンバ式)で説明されているように、型名を省略することができます(ドットは必要です)。
列挙ケースの値を確認するには、Matching Enumeration Values with a Switch Statement(Switch 文を使った列挙値のパターンマッチング)で説明されているように、switch 文を使用します。列挙型は、Enumeration Case Pattern(列挙ケースパターン)で説明されているように、switch 文のケースブロックの列挙ケースのパターンに対してパターンマッチングできます。
GRAMMAR OF AN ENUMERATION DECLARATION enum-declaration → attributesopt access-level-modifieropt union-style-enum enum-declaration → attributesopt access-level-modifieropt raw-value-style-enum union-style-enum → indirectopt enum enum-name generic-parameter-clauseopt type-inheritance-clauseopt generic-where-clauseopt { union-style-enum-membersopt } union-style-enum-members → union-style-enum-member union-style-enum-membersopt union-style-enum-member → declaration | union-style-enum-case-clause | compiler-control-statement union-style-enum-case-clause → attributesopt indirectopt case union-style-enum-case-list union-style-enum-case-list → union-style-enum-case | union-style-enum-case , union-style-enum-case-list union-style-enum-case → enum-case-name tuple-typeopt enum-name → identifier enum-case-name → identifier raw-value-style-enum → enum enum-name generic-parameter-clauseopt type-inheritance-clause generic-where-clauseopt { raw-value-style-enum-members } raw-value-style-enum-members → raw-value-style-enum-member raw-value-style-enum-membersopt raw-value-style-enum-member → declaration | raw-value-style-enum-case-clause | compiler-control-statement raw-value-style-enum-case-clause → attributesopt case raw-value-style-enum-case-list raw-value-style-enum-case-list → raw-value-style-enum-case | raw-value-style-enum-case , raw-value-style-enum-case-list raw-value-style-enum-case → enum-case-name raw-value-assignmentopt raw-value-assignment → = raw-value-literal raw-value-literal → numeric-literal | static-string-literal | boolean-literal

構造体宣言(Structure Declaration)

_構造体宣言_は、名前付きの構造体型をプログラムに導入します。構造体宣言は struct キーワードを使用して宣言され、形式は次のとおりです。
構造体宣言
構造体の本文には、0 個以上の declarations が含まれています。これらの declarations には、格納プロパティと計算プロパティ、型プロパティ、インスタンスメソッド、型メソッド、イニシャライザ、サブスクリプト、タイプエイリアス、さらにはその他の構造体、クラス、アクター、列挙型の宣言を含めることができます。構造体宣言にデイニシャライザまたはプロトコル宣言を含めることはできません。様々な種類の宣言を含む構造体の説明といくつかの例については、Structures and Classes(構造体とクラス)を参照ください。
構造体型は任意の数のプロトコルに準拠できますが、クラス、列挙型、またはその他の構造体を継承することはできません。
宣言された構造体のインスタンスを作成するには、次の 3 つの方法があります。
構造体の宣言されたプロパティを初期化するプロセスは、Initialization(初期化)で説明されています
構造体インスタンスのプロパティには、Accessing Properties(プロパティへのアクセス)で説明されているように、ドット(.)構文を使用してアクセスできます。
構造体は値型です。構造体のインスタンスは、変数または定数に割り当てられたとき、または引数として関数呼び出し時に渡されたときにコピーされます。値型の詳細については、Structures and Enumerations Are Value Types(構造体と列挙型は値型)を参照ください。
Extension Declaration(拡張宣言)で説明されているように、extension を使用して構造体の動作を拡張できます。
GRAMMAR OF A STRUCTURE DECLARATION struct-declaration → attributesopt access-level-modifieropt struct struct-name generic-parameter-clauseopt type-inheritance-clauseopt generic-where-clauseopt struct-body struct-name → identifier struct-body → { struct-membersopt } struct-members → struct-member struct-membersopt struct-member → declaration | compiler-control-statement

クラス宣言(Class Declaration)

_クラス宣言_は、名前付きクラス型をプログラムに導入します。クラス宣言は、class キーワードを使用して宣言され、形式は次のとおりです。
クラス宣言
クラスの本文には、0 個以上の declarations が含まれています。これらの declarations には、格納プロパティと計算プロパティ、インスタンスメソッド、型メソッド、イニシャライザ、単一のデイニシャライザ、サブスクリプト、タイプエイリアス、さらには他のクラス、構造体、アクター、列挙型の宣言を含めることができます。クラス宣言にプロトコル宣言を含めることはできません。様々な種類の宣言を含むクラスの説明といくつかの例については、Structures and Classesを参照ください。
クラス型は、1 つの superclass のみ継承できますが、任意の数のプロトコルに準拠できます。superclass は、class name とコロン(:)の後の最初に表示され、その後に adopted protocols が続きます。ジェネリッククラスは他のジェネリッククラスと非ジェネリッククラスを継承できますが、非ジェネリッククラスは他の非ジェネリッククラスのみ継承できます。コロンの後にジェネリックなスーパークラスの名前を書くときは、ジェネリックパラメータを含めたそのジェネリッククラスの全てを含める必要があります。
Initializer Declaration(イニシャライザ宣言)で説明されているように、クラスには指定イニシャライザと convenience イニシャライザを含めることができます。クラスの指定イニシャライザは、クラスで宣言された全てのプロパティを初期化する必要があり、スーパークラスの指定イニシャライザを呼び出す前に初期化する必要があります。
クラスは、そのスーパークラスのプロパティ、メソッド、サブスクリプト、およびイニシャライザをオーバーライドできます。オーバーライドされたプロパティ、メソッド、サブスクリプト、および指定イニシャライザは、override 修飾子でマークされる必要があります。
サブクラスでもスーパークラスのイニシャライザの実装を必須にするには、スーパークラスのイニシャライザに required 修飾子をマークします。そのイニシャライザのサブクラスの実装にも、required 修飾子でマークする必要があります。
superclass で宣言されたプロパティとメソッドは現在のクラスに継承されますが、superclass で宣言された指定イニシャライザは、サブクラスがAutomatic Initializer Inheritance(自動イニシャライザの継承)で説明されている条件を満たす場合にのみ継承されます。Swift のクラスは、全てに共通する基本クラスを継承しません。
宣言されたクラスのインスタンスを作成するには、次の 2 つの方法があります:
クラスは参照型です。クラスのインスタンスは、変数や定数に割り当てられたとき、または関数呼び出し時に引数として渡されたときに、コピーされるのではなく参照が渡されます。参照型の詳細については、Classes Are Reference Types(クラスは参照型)を参照ください。
Extension Declaration(拡張宣言)で説明されているように、extension を使用してクラス型の動作を拡張できます。
GRAMMAR OF A CLASS DECLARATION class-declaration → attributesopt access-level-modifieropt finalopt class class-name generic-parameter-clauseopt type-inheritance-clauseopt generic-where-clauseopt class-body class-declaration → attributesopt final access-level-modifieropt class class-name generic-parameter-clauseopt type-inheritance-clauseopt generic-where-clauseopt class-body class-name → identifier class-body → { class-membersopt } class-members → class-member class-membersopt class-member → declaration | compiler-control-statement

アクター宣言(Actor Declaration)

アクター宣言は、名前付きのアクター型をプログラムに導入します。アクター宣言は、actor キーワードを使用して宣言され、形式は次のとおりです。
アクター宣言
アクターの本文には、0 個以上の declarations が含まれています。これらの declarations には、格納プロパティと計算プロパテ、インスタンスメソッド、型メソッド、イニシャライザ、単一のデイニシャライザ、サブスクリプト、タイプエイリアス、さらには他のクラス、構造体、列挙型の宣言を含めることができます。様々な種類の宣言を含むアクターの説明といくつかの例については、Actors(アクター)を参照ください。
アクター型は任意の数のプロトコルに準拠できますが、クラス、列挙型、構造体、または他のアクターを継承することはできません。ただし、@objc 属性でマークされたアクターは、暗黙的に NSObjectProtocol プロトコルに準拠し、NSObject のサブタイプとして Objective-C ランタイムに公開されます。
宣言されたアクターのインスタンスを作成するには、次の 2 つの方法があります:
  • Initializers(イニシャライザ)で説明されているように、アクター内で宣言されたイニシャライザの 1 つを呼び出します
  • イニシャライザが宣言されておらず、アクター宣言の全てのプロパティに初期値が指定されている場合は、Default Initializers(デフォルトイニシャライザ)で説明されているように、アクターのデフォルトイニシャライザを呼び出します
デフォルトでは、アクターのメンバはそのアクターに隔離(isolated)されています。メソッドの本文やプロパティの get などのコードは、そのアクター内で実行されます。アクター内のコードは、そのコードが既に同じアクターで実行されることがわかっているため、同期的にやり取りできますが、アクター外のコードは、このコードが別のアクターで非同期に実行されているコードだということを示すために、await をマークする必要があります。KeyPath は、アクターの isolated メンバを参照することはできません。アクターの isolated 格納プロパティは、同期関数に in-out パラメータとして渡すことができますが、非同期関数には渡すことができません。
アクターは、宣言が nonisolated キーワードでマークされている非隔離(nonisolated) メンバを持つこともできます。nonisolated メンバは、アクターの外部のコードのように実行されます。アクターの isolated な状態と同期的にやり取りすることはできませんが、呼び出し元は、使用時に await マークを付けません。
アクターのメンバは、nonisolated または非同期の場合にのみ @objc 属性でマークできます。
アクターの宣言されたプロパティを初期化するプロセスは、Initialization(イニシャライザ)で説明されています。
アクターインスタンスのプロパティには、Accessing Properties(プロパティへのアクセス)で説明されているように、ドット(.)構文を使用してアクセスできます。
アクターは参照型です。アクターのインスタンスは、変数または定数に割り当てられたとき、または関数呼び出し時に引数として渡されたときに、コピーされるのではなく参照が渡されます。参照型の詳細については、Classes Are Reference Types(クラスは参照型)を参照ください。
Extension Declaration(拡張宣言)で説明されているように、extension を使用してアクター型の動作を拡張できます。
GRAMMAR OF A ACTOR DECLARATION actor-declaration → attributesopt access-level-modifieropt actor actor-name generic-parameter-clauseopt type-inheritance-clauseopt generic-where-clauseopt actor-body actor-name → identifier actor-body → { actor-membersopt } actor-members → actor-member actor-membersopt actor-member → declaration | compiler-control-statement

プロトコル宣言(Protocol Declaration)

_プロトコル宣言_は、名前付きのプロトコル型をプログラムに導入します。プロトコル宣言は、protocol キーワードを使用してグローバルスコープで宣言され、形式は次のとおりです。
プロトコル宣言
プロトコルの本文には、プロトコルに準拠する全ての型が満たさなければならない 0 個以上の protocol member declarations が含まれています。特に、プロトコルは、準拠する型が特定のプロパティ、メソッド、イニシャライザ、およびサブスクリプトを実装する必要があることを宣言できます。プロトコルは、_関連型_と呼ばれる特別な種類のタイプエイリアスを宣言することもできます。これにより、プロトコルの様々な宣言間の関係を指定できます。プロトコル宣言には、クラス、構造体、列挙型、またはその他のプロトコル宣言を含めることはできません。_protocol member declarations_の宣言については、下記で詳しく説明します。
プロトコル型は、他の任意の数のプロトコルを継承できます。プロトコル型が他のプロトコルを継承する場合、それら他のプロトコルからの一連の要件が集約され、現在のプロトコルを継承する型は全て、それらの要件全てに準拠する必要があります。プロトコル継承の使用方法の例については、Protocol Inheritance(プロトコル継承)を参照ください。
NOTE Protocol Composition Type(プロトコル合成型)およびProtocol Composition(プロトコル合成)で説明されているように、プロトコル合成型を使用して、複数のプロトコルの要件を集約することもできます。
その型の extension でプロトコルに準拠することにより、事前に宣言された型にプロトコルを準拠させることができます。extension では、準拠したプロトコルの要件を全て実装する必要があります。型が既に全ての要件を実装している場合は、extension の本文を空のままにしておくことができます。
デフォルトでは、プロトコルに準拠する型は、プロトコルで宣言されている全てのプロパティ、メソッド、およびサブスクリプトを実装する必要があります。しかし、これらのプロトコルメンバ宣言に optional 修飾子をマークして、準拠する型の実装を省略することもできます。optional 修飾子は、objc 属性でマークされているメンバにのみ適用でき、objc 属性でマークされているプロトコルのメンバにのみ適用できます。その結果、クラス型のみが、オプショナルのメンバ要件を含むプロトコルに準拠できます。optional 修飾子の使用方法の詳細と、オプショナルのプロトコルメンバにアクセスする方法のガイダンス(例えば、準拠する型がそれらを実装しているかどうかわからない場合など)については、Optional Protocol Requirements(オプショナルのプロトコル要件)を参照ください。
列挙型の場合は、型メンバのプロトコル要件を満たすことができます。具体的には、関連値のない列挙ケースは、Self 型の get-only の型変数のプロトコル要件を満たし、関連値のある列挙ケースは、パラメータとその引数ラベルがケース名と一致する Self を返す関数のプロトコル要件を満たします。例えば:
protocol SomeProtocol {
static var someValue: Self { get }
static func someFunction(x: Int) -> Self
}
enum MyEnum: SomeProtocol {
case someValue
case someFunction(x: Int)
}
プロトコルに準拠できる型をクラス型のみに制限するには、コロン(:)の後の inherited protocols リストに AnyObject プロトコルを含めます。例えば、次のプロトコルはクラス型でのみで準拠できます。
protocol SomeProtocol: AnyObject {
/* プロトコルメンバはここに */
}
同様に AnyObject でマークされたプロトコルを継承するプロトコルは、クラス型でのみ準拠できます。
NOTE プロトコルが objc 属性でマークされている場合、AnyObject はそのプロトコルに暗黙的に準拠します。AnyObject を明示的にマークする必要はありません。
プロトコルは名前付きの型のため、Protocols as Types(型としてのプロトコル)で説明されているように、他の名前付きの型と同じようにコード内で型として使用できることもあります。ただし、プロトコルは実際には指定された要件の実装を提供しないため、プロトコルのインスタンスを構築することはできません。