Swift 6.0 beta 日本語化計画 : Swift 6.0 beta
構造体とクラス
構造体とクラス は、汎用で、プログラムのコードをビルドするとブロックになる柔軟な構築物です。プロパティとメソッドを定義し、定数、変数、そして関数を定義するのと同じ構文を使って、構造体とクラスに、機能を追加します。
他のプログラミング言語とは異なり、Swift では、カスタム構造体やカスタムクラスのために別のインタフェースや実装ファイルを作成する必要はありません。Swift では、構造体やクラスを単一のファイル内で定義し、そのクラスまたは構造体への外部インタフェースは使用する他のコードに自動的に使用可能になります。
Swift の構造体およびクラスは多くの共通点を持っています。両方とも以下のことができます。
詳細については、プロパティ、メソッド、サブスクリプト、初期化、拡張機能、および プロトコル を参照してください。
クラスには、構造体にはない追加の機能があります。
詳細については、継承 、型キャスト、デイニシャライザ、および 自動参照カウント を参照してください。
クラスがサポートする追加の機能は複雑さが増すコストがあります。一般的なガイドラインとして、構造体を好む理由が簡単であるという理由であり、適切で必要なときにクラスを使用します。実際には、これは、定義するカスタム型のほとんどが構造体と列挙型になることを意味します。より詳細な比較については、構造体とクラスの選択 を参照してください。
構造体とクラスは類似の定義構文を持っています。struct キーワードで構造体を導入し、class キーワードでクラスを導入します。どちらも中括弧のペアの中にそれら全体の定義を置きます。
ここで構造体の定義とクラスの定義の例を示します。
上記の例では、ピクセルをベースにしたディスプレイ解像度を記述するために、Resolution という新たな構造体を定義しています。この構造体には、width と height と言う二つの格納されたプロパティがあります。格納されたプロパティは、定数あるいは変数であり、構造体またはクラスの一部として束ねられ、格納されます。この2つのプロパティは、それらに整数 0 の初期値を設定することで、Int 型であることが推測されます。
上記の例では、また、ビデオ表示用の特定のビデオモードを説明するために、VideoMode という新しいクラスも定義しています。このクラスは、4つの格納された変数のプロパティを持っています。最初に、 resolution は、Resolution のプロパティ型を推測する、新しい Resolution の構造体インスタンスで初期化されます。他の3つのプロパティの場合、新しい VideoMode インスタンスは interlaced 設定が false で初期化され("ノンインターレースビデオ" を意味します)、0.0 の再生フレームレート、および name と呼ばれる optional の String 値で初期化されます。それは、optional の型であるため、name プロパティは、自動的に、nil のデフォルト値、または "name のない値" が与えられます。
Resolution 構造体の定義と VideoMode クラスの定義は、Resolution や VideoMode がどう見えるかについて説明するだけです。それら自身は特定の resolution または Video Mode を記載していません。これを行なうには、構造体またはクラスのインスタンスを作成する必要があります。
インスタンスを作成するための構文は、構造体とクラスの両方に非常に似ています。
構造体とクラスは、両方とも新しいインスタンス用のイニシャライザ構文を使用します。イニシャライザ構文の最も単純な形式は、Resolution( ) や VideoMode( ) のように空の括弧が続くクラスまたは構造体の型名を使用します。これは、クラスまたは構造体の新しいインスタンスを作成し、それらのデフォルト値に全てのプロパティは初期化されます。クラスと構造体の初期化は、初期化 で、より詳しく記載されています。
ドット構文 を使用してインスタンスのプロパティにアクセスできます。ドット構文では、スペースを含まない、ピリオド (.) で区切られた、インスタンス名の直後にプロパティ名を書いて下さい。
この例では、someResolution.width は someResolution の width プロパティを参照し、0 のデフォルトの初期値を返します。
VideoMode の resolution プロパティの width プロパティのように、サブプロパティへと層を下がって行けます。
また、変数プロパティに新しい値を割り当てるために、ドット構文を使用する事もできます。
すべての構造体は、自動的に生成される メンバ化イニシャライザ を持っており、これは新しい構造体インスタンスのメンバプロパティを初期化するために使用できます。新しいインスタンスのプロパティの初期値は、名前でメンバ化イニシャライザに渡すことができます。
構造体とは異なり、クラス・インスタンスは、デフォルトのメンバ化イニシャライザを受け取りません。イニシャライザは、初期化 で詳しく説明しています。
値型 は、変数または定数に代入される場合、またはそれが関数に渡されるときにその値が コピー される型です。
実際にこれまでの章を通して広範囲に亘って値型を使用してきました。実際に、Swift の基本的な型のすべては、整数、浮動小数点数、ブール値、文字列、配列、および辞書で、それらは値型であり、それは舞台裏では、構造体として実装されます。
すべての構造体と列挙型は Swift では値型です。これは、作成する全ての構造体と列挙型のインスタンスと、それらがプロパティとして持っている全ての値型は、それらがコード内で渡された場合、常にコピーされることを意味します。
前の例から Resolution の構造体を使用する、この例を考えてみましょう。
この例では、hd と言う定数を宣言し、フル HD ビデオの幅と高さ(幅 1920 ピクセル、高さ 1080 ピクセル) で初期化された Resolution インスタンスにそれを設定します。
その後、cinema と言う変数を宣言し、hd の現在値にそれを設定します。Resolution は構造体であるため、既存のインスタンスの コピー が作成され、この新しいコピーは、cinema に代入されます。hd と cinema は今や同じ幅と高さを持っているにもかかわらず、それらは舞台裏では2つの全く異なるインスタンスです。
次に、cinema の width プロパティは、デジタルシネマ投影に使用される、わずかに広い 2K 規格の幅 (幅 2048 ピクセル、高さ 1080 ピクセル) に修正されます。
cinema の width プロパティをチェックすると、それが実際に 2048 に変更されたことがわかります。
しかし、元の hd インスタンスの width プロパティは、まだ古い値の 1920 のままです:
cinema が hd の現在値を与えられたとき、hd に格納された 値 は、新しい cinema インスタンスにコピーされました。最終結果は、2つの完全に異なるインスタンスとなり、同じ数値を含みます。しかし、それらは別々のインスタンスであるため、cinema の width に 2048 を設定しても、下図に示したように、hd に格納されている width には影響しません。
同じ動作は列挙型にも適用されます。
rememberedDirection が currentDirection の値を代入された時は、実際にはその値のコピーに設定されます。 currentDirection の値を変更しても、その後それは rememberedDirection に格納されていた元の値のコピーには影響しません。
値型とは異なり、変数や定数に代入される時やそれらが関数に渡された時は、参照型 はコピーされ ません。コピーではなく、同じ既存のインスタンスへの参照が代わりに使用されます。
ここで、上記で定義された VideoMode クラスを使用した例を挙げます。
この例では、tenEighty という新しい定数を宣言し、VideoMode クラスの新しいインスタンスを参照するように設定します。ビデオモードは、以前からの 1920 * 1080 の HD 解像度のコピーが代入されています。これは、インターレースと設定され、その名前は "1080i" となり、そのフレームレートは毎秒 25.0 フレームに設定されています。
次に、tenEighty は alsoTenEighty と言う新しい定数に代入され、alsoTenEighty の frmae rate (フレームレート) が変更されます。
クラスは参照型なので、tenEighty と alsoTenEighty は、実際にはどちらも 同じ VideoMode インスタンスを参照しています。事実上、下図に示したようにそれらは同じ一つのインスタンスの2つの異なる名前に過ぎません。
tenEighty の frameRate プロパティをチェックすると、それは正しく基礎となる VideoMode インスタンスから 30.0 の新しいフレームレートを報告することを示します。
この例では、参照型を推論するのがより難しくなる可能性も示しています。tenEighty と alsoTenEighty があなたのプログラムコード内で非常に離れていた場合、ビデオモードが変更されるすべての方法を見つけるのは難しいかもしれません。tenEighty を使用する場合は常に、alsoTenEighty を使用するコードについてもあなたは考えなければなりませんし、逆もまた同様です。対照的に、値型は、同じ値を操作するすべてのコードがソースファイル内で接近しているため、推論するのが容易です。
tenEighty と alsoTenEighty は、変数ではなく、定数 として宣言されていることに注意してください。しかし、まだ tenEighty.frameRate と alsoTenEighty.frameRate を変更できるのは、tenEighty と alsoTenEighty 定数の値それ自体は実際には変更されないからです。tenEighty と alsoTenEighty 自身は VideoMode インスタンスを "格納" せず、代わりに、それらは両方とも舞台裏で VideoMode インスタンスを 参照 しています。変更されるのは、その VideoMode への定数の参照値ではなく、基本となる VideoMode の frameRate プロパティです。
クラスは参照型であるため、複数の定数や変数は舞台裏で、クラスの同じ一つのインスタンスを参照することが可能です。(構造体と列挙型が定数または変数に割り当てられている場合、または関数に渡される場合、常にコピーされるので、同じことは構造体と列挙型には当てはまりません。)
2つの定数または変数がクラスのまったく同じインスタンスとを参照しているかどうかを見つけるのは時々役立ちます。これを有効にするのに、Swift は、2つの ID 演算子を提供しています。
これらの演算子を使用して、2つの定数または変数が同じ一つのインスタンスを参照しているかどうかチェックして下さい。
"全く同一である" (3つの等号、つまり === によって表される) 事は "等しい” (2つの等号、つまり == によって表される) と同じことを意味するものではないことに注意してください。同一である とは、クラス型の 2 つの定数または変数がまったく同じクラスインスタンスを参照していることを意味します。等しい とは、型の設計者により定義されたように、いくつかの適切な意味で 等しく、2 つのインスタンスが等しいか同等の値であることを意味します。
独自のカスタム構造体とクラスを定義する際には、2つのインスタンスが等しいという資格があるかを決めるのはあなたの責任です。== と != の演算子の独自の実装を定義するプロセスは 等価演算子 に説明されています。
C、C++、または Objective-C の経験をお持ちの場合は、これらの言語では、ポインタ をメモリ内のアドレスを参照するために使用することを知っているでしょう。いくつかの参照型のインスタンスを参照する Swift の定数または変数は、C でのポインタに似ていますが、メモリ内のアドレスへの直接のポインタではなく、また参照を作成していることを示すためにアスタリスク (*) を書く必要もありません。代わりに、これらの参照は、Swift の他の定数または変数のように定義されています。Swift の標準ライブラリは、ポインタを直接操作する必要がある場合に使用できるポインタとバッファ型を提供します。手動でメモリー管理 を参照してください。