構造体
構造体とは
継承できないクラスのことです。
クラスと大きく違う点は、引数としてこれらのクラス・構造体がオブジェクトとして渡された際に、
クラスは参照渡し(メモリの位置情報を渡し、その位置が参照され直接値を扱う)となり、
構造体は値渡し(メモリの中の情報はそのままで、コピーが扱われる)になることです。
クラスは参照型、構造体は値型と呼ばれます。
つまり、構造体は情報を変更されることなく安全にデータを保持したいときに使います。
関数Aが関数Bを呼び出す様子を表しています。このクラスとの違いを理解して、使いこなすようにするとよいでしょう。
構造体の宣言 struct 構造体名 { ~処理~ }
1 2 3 4 5 6 7 8 |
// 構造体の定義 struct Dog { var name: String? // 構造体内でのプロパティの宣言 func bark (value: String) { // 構造体内でのメソッドの宣言 print(value) } } |
基本的に使い方はクラスと同じです。
しかし、下記の点にて扱い・挙動が違いますので押さえておきましょう。
イニシャライザが自動生成される
次のインスタンス代入時の書き方に注目してください。
1 2 3 4 5 6 7 |
struct Dog { var name: String? var type: String? var birthday: String? } let myDog = Dog(name: "ポチ", type: "シェパード", birthday: "2020/04/01") print(myDog.name) |
構造体では、プロパティを引数にもつイニシャライザが自動的に生成されるため、init()...を書かなくとも、上記のようにプロパティを設定することができます。確認してみてください。
インスタンスをletで宣言した時に、プロパティ値が再代入不可となる
次の、最後の行のコード(インスタンスから構造体のプロパティ値を再代入しようとした時)を確認してみてください。
1 2 3 4 5 6 7 |
struct Dog { var name: String? var type: String? var birthday: String? } let myDog = Dog(name: "ポチ", type: "シェパード", birthday: "2020/04/01") myDog.name = "ジョン" |
エラーが発生しますね。
myDogインスタンスのプロパティは、一度定めたら値が再代入できなくなっています。
ではその状態で、「structをclassに変更」「イニシャライザの記載」をして、構造体をクラスに変更してみてください。
myDogのインスタンスはletで宣言しているにも関わらず、再代入ができました。なぜでしょうか。
「参照型」であるクラスは、myDogに「Dogのメモリ上の位置情報」が入っているからです。
let [Dogの位置情報] ←この情報を頼りに"ポチ"、"ジョン"といった値を届けにいく。
つまり、letの効力はあくまで位置情報(どのクラスが入っているか)の書き換えであり、プロパティの書き換えに対して効力があるわけでは無いのです。
「値型」である構造体は、myDogに「Dogのコピー情報」が入っています。
let [Dogのコピー情報]←この中に直接"ポチ"、”ジョン”といった値を入れる
letの効力は、Dogのコピー情報の書き換えに対してあるため、コピーDogの中のプロパティ値ももちろん書き換えることができません。いつも使っている定数と同じように「一度定めたら変えられない」となります。
このように細かな違いを押さえてうまく使い分けましょう。