宣言(Declarations)
最終更新日: 2021/7/2 原文: 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 を通して対応する値にバインドされます。
1
let (firstNumber, secondNumber) = (10, 42)
Copied!
この例では、firstNumber は値 10 の名前付き定数で、secondNumber42 の名前付き定数です。両方の定数は独立して使用できます。
1
print("The first number is \(firstNumber).")
2
// The first number is 10.
3
print("The second number is \(secondNumber).")
4
// The second number is 42.
Copied!
型注釈(: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 を呼び出さずに新しい値が格納されます。下記の例は、スーパークラスで定義され、オブザーバを追加するためにそのサブクラスでオーバーライドされた計算プロパティを示しています:
1
class Superclass {
2
private var xValue = 12
3
var x: Int {
4
get { print("Getter was called"); return xValue }
5
set { print("Setter was called"); xValue = newValue }
6
}
7
}
8
9
// このサブクラスは オブザーバ の oldValue を参照していません
10
// SuperClass の get は、値を出力するために一度だけ呼び出されます。
11
class New: Superclass {
12
override var x: Int {
13
didSet { print("New value \(x)") }
14
}
15
}
16
let new = New()
17
new.x = 100
18
// Setter was called
19
// Getter was called
20
// New value 100
21
22
// このサブクラスはそのオブザーバの oldValue を参照しているので、スーパークラスの
23
// get はセッターの前に一度呼び出され、また値を出力します
24
class NewAndOld: Superclass {
25
override var x: Int {
26
didSet { print("Old value \(oldValue) - new value \(x)") }
27
}
28
}
29
let newAndOld = NewAndOld()
30
newAndOld.x = 200
31
// Getter was called
32
// Setter was called
33
// Getter was called
34
// Old value 12 - new value 200
Copied!
より詳細な情報やプロパティオブザーバの使用方法の例は、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 は、名前付き型または複合型にすることができます。タイプエイリアスは新しい型を作成しません。それらは単に名前が既存の型を参照することを可能にします。
タイプエイリアス宣言は、ジェネリックパラメータを使用して既存のジェネリック型に名前を付けることができます。そのタイプエイリアスは、既存の型のジェネリックパラメータの一部または全部を使って具象型を提供できます。例えば:
1
typealias StringDictionary<Value> = Dictionary<String, Value>
2
3
// 以下の辞書は同じ型を持っています
4
var dictionary1: StringDictionary<Int> = [:]
5
var dictionary2: Dictionary<String, Int> = [:]
Copied!
タイプエイリアスがジェネリックパラメータで宣言されると、それらのパラメータの制約は既存の型のジェネリックパラメータの制約と正確に一致する必要があります。例えば:
1
typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>
Copied!
タイプエイリアスと既存の型は互換的に使用される可能性があるため、タイプエイリアスは追加のジェネリック制約を導入できません。
タイプエイリアスは、宣言から全てのジェネリックパラメータを省略することで、既存の型のジェネリックパラメータを流用できます。例えば、ここで宣言されている Diccionario というタイプエイリアスは、Dictionary と同じジェネリックパラメータと制約を持ちます。
1
typealias Diccionario = Dictionary
Copied!
プロトコル宣言の内部では、タイプエイリアスは頻繁に使用される型に短くて便利な名前を付けることができます。例えば:
1
protocol Sequence {
2
associatedtype Iterator: IteratorProtocol
3
typealias Element = Iterator.Element
4
}
5
6
func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
7
// ...
8
}
Copied!
このタイプエイリアスがないと、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 つを持つカンマ区切りのリストです。関数呼び出し内の引数の順序は、関数の宣言内のパラメータの順序と一致する必要があります。パラメータリスト内の最もシンプルなエントリの形式は次のとおりです:
パラメータリスト内の最もシンプルなエントリ
パラメータには、関数本文内で使用されている名前、および関数またはメソッドを呼び出すときに使用される引数ラベルがあります。デフォルトでは、パラメータ名は引数ラベルとしても使用されます。例えば:
1
func f(x: Int, y: Int) -> Int { return x + y }
2
f(x: 1, y: 2) // x と y の両方にラベルがあります
Copied!
次のいずれかの形式で、引数ラベルのデフォルトの動作を上書きできます。
引数ラベルのデフォルトの動作を上書き
パラメータ名の前の名前は、パラメータの明示的な引数ラベルで、パラメータ名とは異なる可能性があります。関数呼び出しまたはメソッド呼び出し時は、対応する引数に指定された引数ラベルを使用する必要があります。
パラメータ名の前にアンダースコア(_)を付けると、引数ラベルが省略されます。関数呼び出しまたはメソッド呼び出し時は、対応する引数に、ラベルを付けてはなりません。
1
func repeatGreeting(_ greeting: String, count n: Int) { /* n 回あいさつ */ }
2
repeatGreeting("Hello, world!", count: 2) // count は ラベルあち, greeting は ラベルなし
Copied!

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 パラメータを変えることなくキャプチャする必要がある場合は、キャプチャリストを使用して、パラメータを不変なものとして明示的にキャプチャします。
1
func someFunction(a: inout Int) -> () -> Int {
2
return { [a] in return a + 1 }
3
}
Copied!
in-out パラメータをキャプチャして変更する必要がある場合は、マルチスレッドコードで関数が返される前に全ての変更が終了することを保証するように、明示的にローカルコピーを使用してください。
1
func multithreadedFunction(queue: DispatchQueue, x: inout Int) {
2
// 手動でローカルコピーを作成します
3
var localX = x
4
defer { x = localX }
5
6
// localXを非同期的に操作してから、戻る前に待機します
7
queue.async { someMutatingOperation(&localX) }
8
queue.sync {}
9
}
Copied!
より多くの議論と in-out パラメータの例については、In-Out Parameters(In-Out パラメータ)を参照ください。

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

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

特殊な種類のメソッド(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:) も有効です。
次の関数呼び出しは同等です:
1
struct CallableStruct {
2
var value: Int
3
func callAsFunction(_ number: Int, scale: Int) {
4
print(scale * (number + value))
5
}
6
}
7
let callable = CallableStruct(value: 100)
8
callable(4, scale: 2)
9
callable.callAsFunction(4, scale: 2)
10
// 両方の関数は印刷 208 を出力します
Copied!
call-as-function メソッドと dynamicCallable 属性のメソッドは、型システムにどのくらいの情報を与え、実行時にどのくらい動的な動作が可能かの間で異なるトレードオフがあります。call-as-function メソッドを宣言すると、引数の数、および各引数の型とラベルを指定します。dynamicCallable 属性のメソッドは、引数の配列を保持するために使用される型のみを指定できます。
call-as-function メソッド、または dynamicCallable 属性のメソッドを定義することは、任意のコンテキスト内で関数呼び出し以外の関数のようにその型のインスタンスを使用してはいけません。例えば:
1
let someFunction1: (Int, Int) -> Void = callable(_:scale:) // エラー
2
let someFunction2: (Int, Int) -> Void = callable.callAsFunction(_:scale:)
Copied!
subscript(dynamicMember:) は、dynamicMemberLookupで説明されているように、メンバを検索するための糖衣構文(シンタックスシュガー)です。

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

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

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

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

非同期関数と非同期メソッド(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 つ以上の列挙ケースで構成され、カンマ(,)で区切られます。各ケースの名前は一意にする必要があります。各ケースでは、特定の型の値を格納するように指定することもできます。これらの型は、ケースの名前の直後にある、関連値 のタプルで指定できます。
関連値を持つ列挙ケースは、指定された関連値を使用して列挙型のインスタンスを作成する関数として使用できます。また、関数と同様に、列挙ケースへの参照を取得して、後のコードで使用できます。
1
enum Number {
2
case integer(Int)
3
case real(Double)
4
}
5
let f = Number.integer
6
// f は (Int) -> Number 型の関数です
7
8
// f を適用して、整数値を持つ Number インスタンスの配列を作成します
9
let evenInts: [Number] = [0, 2, 4, 6].map(f)
Copied!
詳細および関連値型を持つケースの例については、Associated Values(関連値)を参照ください。

再帰列挙型(Enumerations with Indirection)

列挙型は再帰的な構造を持つことができます。つまり、列挙型自体のインスタンスの値をケースの関連値として持つことができます。ただし、列挙型のインスタンスは値型のセマンティクスです。つまり、不変のメモリレイアウトを持っています。再帰をサポートするには、コンパイラが間接層を挿入する必要があります。
特定の列挙ケースの間接層を挿入するには、indirect 修飾子でマークします。indirect ケースには、関連値が必要です。
1
enum Tree<T> {
2
case empty
3
indirect case node(value: T, left: Tree, right: Tree)
4
}
Copied!
関連値を持つ列挙型の全てのケースで 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 が暗黙的に割り当てられます。
1
enum ExampleEnum: Int {
2
case a, b, c = 5, d
3
}
Copied!
上記の例では、ExampleEnum.a の Raw Value は 0 で、ExampleEnum.b1 です。また、ExampleEnum.c の値は明示的に 5 に設定されているため、ExampleEnum.d の値は自動的に 5 からインクリメントされます。したがって、6 です。
Raw Value 型が文字列として指定されていて、ケースに値が明示的に割り当てない場合、割り当てられていない各ケースには、そのケースの名前と同じテキストの文字列が暗黙的に割り当てられます。
1
enum GamePlayMode: String {
2
case cooperative, individual, competitive
3
}
Copied!
上記の例では、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 には、格納プロパティと計算プロパティ、型プロパティ、インスタンスメソッド、型メソッド、イニシャライザ、subscript、タイプエイリアス、さらにはその他の構造体、クラス、アクター、列挙型の宣言を含めることができます。構造体宣言にデイニシャライザまたはプロトコル宣言を含めることはできません。様々な種類の宣言を含む構造体の説明といくつかの例については、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 には、格納プロパティと計算プロパティ、インスタンスメソッド、型メソッド、イニシャライザ、単一のデイニシャライザ、subscript、タイプエイリアス、さらには他のクラス、構造体、アクター、列挙型の宣言を含めることができます。クラス宣言にプロトコル宣言を含めることはできません。様々な種類の宣言を含むクラスの説明といくつかの例については、Structures and Classesを参照ください。
クラス型は、1 つの superclass のみ継承できますが、任意の数のプロトコルに準拠できます。superclass は、class name とコロン(:)の後の最初に表示され、その後に adopted protocols が続きます。ジェネリッククラスは他のジェネリッククラスと非ジェネリッククラスを継承できますが、非ジェネリッククラスは他の非ジェネリッククラスのみ継承できます。コロンの後にジェネリックなスーパークラスの名前を書くときは、ジェネリックパラメータを含めたそのジェネリッククラスの全てを含める必要があります。
Initializer Declaration(イニシャライザ宣言)で説明されているように、クラスには指定イニシャライザと convenience イニシャライザを含めることができます。クラスの指定イニシャライザは、クラスで宣言された全てのプロパティを初期化する必要があり、スーパークラスの指定イニシャライザを呼び出す前に初期化する必要があります。
クラスは、そのスーパークラスのプロパティ、メソッド、subscript、およびイニシャライザをオーバーライドできます。オーバーライドされたプロパティ、メソッド、subscript、および指定イニシャライザは、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 には、格納プロパティと計算プロパテ、インスタンスメソッド、型メソッド、イニシャライザ、単一のデイニシャライザ、subscript、タイプエイリアス、さらには他のクラス、構造体、列挙型の宣言を含めることができます。様々な種類の宣言を含むアクターの説明といくつかの例については、Actors(アクター)を参照ください。
アクター型は任意の数のプロトコルに準拠できますが、クラス、列挙型、構造体、または他のアクターを継承することはできません。ただし、@objc 属性でマークされたアクターは、暗黙的に NSObjectProtocol プロトコルに準拠し、NSObject のサブタイプとして Objective-C ランタイムに公開されます。
宣言されたアクターのインスタンスを作成するには、次の 2 つの方法があります:
  • Initializers(イニシャライザ)で説明されているように、アクター内で宣言されたイニシャライザの 1 つを呼び出します
  • イニシャライザが宣言されておらず、アクター宣言の全てのプロパティに初期値が指定されている場合は、Default Initializers(デフォルトイニシャライザ)で説明されているように、アクターのデフォルトイニシャライザを呼び出します
デフォルトでは、アクターのメンバはそのアクターに隔離(isolated)されています。メソッドの本文やプロパティの get などのコードは、そのアクター内で実行されます。アクター内のコードは、そのコードが既に同じアクターで実行されることがわかっているため、同期的にやり取りできますが、アクター外のコードは、このコードが別のアクターで非同期に実行されているコードだということを示すために、await をマークする必要があります。key path は、アクターの 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 が含まれています。特に、プロトコルは、準拠する型が特定のプロパティ、メソッド、イニシャライザ、および subscript を実装する必要があることを宣言できます。プロトコルは、_関連型_と呼ばれる特別な種類のタイプエイリアスを宣言することもできます。これにより、プロトコルの様々な宣言間の関係を指定できます。プロトコル宣言には、クラス、構造体、列挙型、またはその他のプロトコル宣言を含めることはできません。_protocol member declarations_の宣言については、下記で詳しく説明します。
プロトコル型は、他の任意の数のプロトコルを継承できます。プロトコル型が他のプロトコルを継承する場合、それら他のプロトコルからの一連の要件が集約され、現在のプロトコルを継承する型は全て、それらの要件全てに準拠する必要があります。プロトコル継承の使用方法の例については、Protocol Inheritance(プロトコル継承)を参照ください。
NOTE Protocol Composition Type(プロトコル合成型)およびProtocol Composition(プロトコル合成)で説明されているように、プロトコル合成型を使用して、複数のプロトコルの要件を集約することもできます。
その型の extension でプロトコルに準拠することにより、事前に宣言された型にプロトコルを準拠させることができます。extension では、準拠したプロトコルの要件を全て実装する必要があります。型が既に全ての要件を実装している場合は、extension の本文を空のままにしておくことができます。
デフォルトでは、プロトコルに準拠する型は、プロトコルで宣言されている全てのプロパティ、メソッド、および subscript を実装する必要があります。しかし、これらのプロトコルメンバ宣言に optional 修飾子をマークして、準拠する型の実装を省略することもできます。optional 修飾子は、objc 属性でマークされているメンバにのみ適用でき、objc 属性でマークされているプロトコルのメンバにのみ適用できます。その結果、クラス型のみが、オプショナルのメンバ要件を含むプロトコルに準拠できます。optional 修飾子の使用方法の詳細と、オプショナルのプロトコルメンバにアクセスする方法のガイダンス(例えば、準拠する型がそれらを実装しているかどうかわからない場合など)については、Optional Protocol Requirements(オプショナルのプロトコル要件)を参照ください。
列挙型の場合は、型メンバのプロトコル要件を満たすことができます。具体的には、関連値のない列挙ケースは、Self 型の get-only の型変数のプロトコル要件を満たし、関連値のある列挙ケースは、パラメータとその引数ラベルがケース名と一致する Self を返す関数のプロトコル要件を満たします。例えば:
1
protocol SomeProtocol {
2
static var someValue: Self { get }
3
static func someFunction(x: Int) -> Self
4
}
5
enum MyEnum: SomeProtocol {
6
case someValue
7
case someFunction(x: Int)
8
}
Copied!
プロトコルに準拠できる型をクラス型のみに制限するには、コロン(:)の後の inherited protocols リストに AnyObject プロトコルを含めます。例えば、次のプロトコルはクラス型でのみで準拠できます。
1
protocol SomeProtocol: AnyObject {
2
/* プロトコルメンバはここに */
3
}
Copied!
同様に AnyObject でマークされたプロトコルを継承するプロトコルは、クラス型でのみ準拠できます。
NOTE プロトコルが objc 属性でマークされている場合、AnyObject はそのプロトコルに暗黙的に準拠します。AnyObject を明示的にマークする必要はありません。
プロトコルは名前付きの型のため、Protocols as Types(型としてのプロトコル)で説明されているように、他の名前付きの型と同じようにコード内で型として使用できることもあります。ただし、プロトコルは実際には指定された要件の実装を提供しないため、プロトコルのインスタンスを構築することはできません。
Delegation(委譲)で説明されているように、クラスまたは構造体のデリゲートが実装するべきメソッドを宣言するためにプロトコルを使用できます。
GRAMMAR OF A PROTOCOL DECLARATION protocol-declaration → attributesopt access-level-modifieropt protocol protocol-name type-inheritance-clauseopt generic-where-clauseopt protocol-body protocol-name → identifier protocol-body → { protocol-membersopt } protocol-members → protocol-member protocol-membersopt protocol-member → protocol-member-declaration | compiler-control-statement protocol-member-declaration → protocol-property-declaration protocol-member-declaration → protocol-method-declaration protocol-member-declaration → protocol-initializer-declaration protocol-member-declaration → protocol-subscript-declaration protocol-member-declaration → protocol-associated-type-declaration protocol-member-declaration → typealias-declaration

プロトコルプロパティ宣言(Protocol Property Declaration)

プロトコルは、プロトコル宣言の本文に_プロトコルプロパティ宣言_を含めることによって準拠する型がプロパティを実装する必要があることを宣言します。プロトコルプロパティ宣言には、変数宣言の特別な形式があります。
Protocol Property Declaration
他のプロトコルメンバ宣言と同様に、これらのプロパティ宣言は、プロトコルに準拠する型の get と set の要件のみを宣言します。その結果、get または set を、プロトコルの宣言で直接実装することはありません。
準拠する型は get と set の要件を様々な方法で満たすことができます。プロパティ宣言に get キーワードと set キーワードの両方が含まれている場合、準拠する型は、格納変数プロパティ、または読み取りと書き込みの両方が可能な計算プロパティ(つまり、get と set の両方を実装するプロパティ)を使用して実装できます。ただし、そのプロパティ宣言は、定数プロパティまたは読み取り専用の計算プロパティとして実装することはできません。プロパティ宣言に get キーワードのみが含まれている場合は、任意の種類のプロパティを実装できます。プロトコルのプロパティ要件を実装した例については、Property Requirements(プロパティ要件)を参照ください。
プロトコル宣言で型プロパティ要件を宣言するには、static キーワードでプロパティ宣言をマークします。プロトコルに準拠する構造体と列挙型は、static キーワードを使用してプロパティを宣言し、プロトコルに準拠するクラスは、static または class キーワードを使用してプロパティを宣言します。構造体、列挙型、またはクラスにプロトコルの準拠を追加する extension は、拡張する型と同じキーワードを使用します。型プロパティ要件のデフォルト実装を提供する extension は、static キーワードを使用します。
Variable Declaration(変数宣言)も参照ください。
GRAMMAR OF A PROTOCOL PROPERTY DECLARATION protocol-property-declaration → variable-declaration-head variable-name type-annotation getter-setter-keyword-block

プロトコルメソッド宣言(Protocol Method Declaration)

プロトコルは、プロトコル宣言の本文にプロトコルメソッド宣言を含めることによって、準拠する型がそのメソッドを実装する必要があることを宣言します。プロトコルメソッド宣言は、関数宣言と同じ形式ですが、2 つの例外があります。関数本文が含まれていないことと、関数宣言の一部としてデフォルトパラメータを指定できないことです。プロトコルのメソッド要件を実装した例については、Method Requirements(メソッド要件)を参照ください。
プロトコル宣言でクラスまたは静的メソッドの要件を宣言するには、static 修飾子を使用してメソッド宣言をマークします。プロトコルに準拠する構造体と列挙型は、static キーワードを使用してメソッドを宣言し、プロトコルに準拠するクラスは、static または class キーワードを使用してメソッドを宣言します。構造体、列挙型、またはクラスにプロトコルの準拠を追加する extension は、拡張する型と同じキーワードを使用します。型メソッド要件のデフォルト実装を提供する extension は、static キーワードを使用します。
Function Declaration(関数宣言)も参照ください。
GRAMMAR OF A PROTOCOL METHOD DECLARATION protocol-method-declaration → function-head function-name generic-parameter-clauseopt function-signature generic-where-clauseopt

プロトコルイニシャライザ宣言(Protocol Initializer Declaration)

プロトコルは、プロトコル宣言の本文にプロトコルイニシャライザ宣言を含めることにより、準拠する型がイニシャライザを実装する必要があることを宣言します。プロトコルイニシャライザ宣言は、イニシャライザの本文が含まれていないことを除いて、イニシャライザ宣言と同じ形式です。
準拠する型は、失敗しないイニシャライザまたは init! 形式の失敗可能イニシャライザを実装することにより、プロトコルの失敗しないイニシャライザの要件を満たすことができます。準拠する型は、任意のイニシャライザを実装することにより、プロトコルの失敗可能イニシャライザの要件を満たすことができます。
クラスがプロトコルのイニシャライザ要件を満たすためのイニシャライザを実装する場合、クラスが final 修飾子でマークされていない場合、イニシャライザは required 修飾子をマークする必要があります。
GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION protocol-initializer-declaration → initializer-head generic-parameter-clauseopt parameter-clausethrowsopt generic-where-clauseopt protocol-initializer-declaration → initializer-head generic-parameter-clauseopt parameter-clauserethrows generic-where-clauseopt

プロトコル subscript 宣言(Protocol Subscript Declaration)

プロトコルは、プロトコル宣言の本文にプロトコル subscript 宣言を含めることによって準拠する型が subscript を実装する必要があることを宣言します。プロトコル subscript 宣言には、特殊な形式の subscript 宣言があります:
プロトコルsubscript宣言
subscript 宣言は、プロトコルに準拠するために最低限必要な get および set の要件のみを宣言します。subscript 宣言に get キーワードと set キーワードの両方が含まれている場合、準拠する型は get 句と set 句の両方を実装する必要があります。subscript 宣言に get キーワードのみが含まれている場合、準拠する型は_少なくとも_ get 句を実装する必要があり、任意で set 句を実装できます。
プロトコル宣言で静的 subscript 要件を宣言するには、static 修飾子を使用して subscript 宣言をマークします。プロトコルに準拠する構造体と列挙型は、static キーワードを使用して subscript を宣言し、プロトコルに準拠するクラスは、static または class キーワードを使用して subscript を宣言します。構造体、列挙型、またはクラスにプロトコルの準拠を追加する extension は、拡張する型と同じキーワードを使用します。静的 subscript 要件のデフォルト実装を提供する extension は、static キーワードを使用します。
GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION protocol-subscript-declaration → subscript-head subscript-result generic-where-clauseopt getter-setter-keyword-block

プロトコル関連型宣言(Protocol Associated Type Declaration)

プロトコルは、associatedtype キーワードを使用して関連型を宣言します。関連型は、プロトコルの宣言の一部として使用される型の別名を提供します。関連型は、ジェネリックパラメータ句の型パラメータに似ていますが、宣言されているプロトコルでは Self に関連付けられています。このコンテキストでは、Self はプロトコルに準拠する最終的な型を指します。詳細と例については、Associated Types(関連型)を参照ください。
プロトコル宣言でジェネリック where 句を使用して、関連型を再宣言せずに、別のプロトコルから継承された関連型に制約を追加できます。例えば、下記の SubProtocol の宣言は同等です:
1
protocol SomeProtocol {
2
associatedtype SomeType
3
}
4
5
protocol SubProtocolA: SomeProtocol {
6
//この構文は警告を生成します
7
associatedtype SomeType: Equatable
8
}
9
10
//この構文が推奨されます
11
protocol SubProtocolB: SomeProtocol where SomeType: Equatable { }
Copied!
GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION protocol-associated-type-declaration → attributesopt access-level-modifieropt associatedtype typealias-name type-inheritance-clauseopt typealias-assignmentopt generic-where-clauseopt

イニシャライザ宣言(Initializer Declaration)

_イニシャライザ宣言_は、クラス、構造体、または列挙型のイニシャライザをプログラムに導入します。イニシャライザ宣言は、init キーワードを使用して宣言され、2 つの基本的な形式があります。
構造体、列挙型、およびクラス型には任意の数のイニシャライザを含めることができますが、クラスイニシャライザのルールと関連する動作は異なります。構造体や列挙型とは異なり、クラスには、Initialization(イニシャライザ)で説明されているように、指定イニシャライザと convenience イニシャライザの 2 種類のイニシャライザがあります。
次の形式は、構造体、列挙型、およびクラスの指定イニシャライザを宣言しています:
イニシャライザ宣言
クラスの指定イニシャライザは、クラスの全てのプロパティを直接初期化します。同じクラスの他のイニシャライザを呼び出すことはできません。クラスにスーパークラスがある場合は、スーパークラスの指定イニシャライザの 1 つを呼び出す必要があります。クラスがそのスーパークラスからプロパティを継承する場合、これらのプロパティのいずれかを現在のクラスで設定または変更する前に、スーパークラスの指定イニシャライザの 1 つを呼び出す必要があります。
指定イニシャライザは、クラス宣言のコンテキストでのみ宣言できるため、extension に追加することはできません。
構造体および列挙型のイニシャライザは、他の宣言されたイニシャライザを呼び出して、初期化プロセスの一部または全てを委譲できます。
クラスの convenience イニシャライザを宣言するには、convenience 修飾子を使用してイニシャライザ宣言をマークします。
convenience イニシャライザ宣言
convenience イニシャライザは、初期化プロセスを別の convenience イニシャライザまたはクラスの指定イニシャライザの 1 つに委譲できます。つまり、初期化プロセスは、最終的にクラスのプロパティを初期化するために、指定イニシャライザを呼び出して終える必要があります。convenience イニシャライザは、スーパークラスのイニシャライザを呼び出すことはできません。
全てのサブクラスがあるイニシャライザを実装することを必須とするために、指定および convenience イニシャライザに required 修飾子をマークすることができます。その場合、サブクラスのイニシャライザの実装にも、required 修飾子をマークする必要があります。
デフォルトでは、スーパークラスで宣言されたイニシャライザはサブクラスに継承されません。ただし、サブクラスが格納されている全てのプロパティをデフォルト値で初期化し、独自のイニシャライザを定義しない場合、サブクラスはスーパークラスの全てのイニシャライザを継承します。サブクラスがスーパークラスの全ての指定イニシャライザをオーバーライドする場合、サブクラスはスーパークラスの convenience イニシャライザを継承します。
メソッド、プロパティ、および subscript と同様に、オーバーライドされた指定イニシャライザを override 修飾子でマークする必要があります。
NOTE required 修飾子を使用してイニシャライザをマークする場合、サブクラスでそのイニシャライザをオーバーライドするときに、override 修飾子をマークする必要はありません。
関数やメソッドと同様に、イニシャライザはエラーをスローまたは再スローできます。また、関数やメソッドと同様に、イニシャライザのパラメータの後に throws または rethrows キーワードを使用して、適切な動作を示します。</