「USBを挿すときに最初の1回目で成功する確率」と「宝くじが当たる確率」は一緒だと思っています。まいど、メモリアインクのふくしまです!
今回はSwiftにおける構造体(Struct)について解説していきます!
この記事を読んでわかること…
・構造体(Struct)とは?
・構造体の基本的な使い方
・クラス(Class)と構造体(Struct)の違い・使い分け
構造体(Struct)って何?
構造体(Struct)とは、関連するデータ(プロパティやメソッド)を一つの単位としてグループ化し、コード内で簡単に使用できるようにするための方法の一つです。
データをカプセル化し、設計書としての役割を果たすという意味では、クラスに似た機能ではあるものの、いくつか重要な違いがありますので、その違いについても後述します!(「クラス(Class)と構造体(Struct)の違い」で解説)。
カプセル化とは…
クラスや構造体内のデータ(プロパティ)とそのデータを操作する方法(メソッド)を一つの単位にまとめるプロセスを指します。カプセル化の主な目的は、オブジェクト(インスタンス化する前の未実体の状態のモノ)の詳細を隠蔽し、外部からの直接的なアクセスを制限することによって、オブジェクトの整合性を保つことです。
クラスについては、以下リンクの記事で解説しています。
クラスの概念やインスタンス化について理解できるかと思いますので、是非ともご一読ください!
構造体の基本的な使い方
ここでは構造体の基本的な使い方を解説します!
構造体の定義の仕方
構造体はstruct
キーワードを使用して定義されます。プロパティとメソッドを含むことができます。
struct Car {
// プロパティ
var make: String
var model: String
var year: Int
// メソッド
func displayDetails() {
print("Make: \(make), Model: \(model), Year: \(year)")
}
}
「Car(車)」の構造体(設計書)を定義しました。
3〜5行目にこの構造体におけるプロパティを定義しています(メーカー、車種、年式)
8〜10行目で車の詳細を表示するためのメソッドを定義しています(displayDetails())
今回の例のように構造体の定義内に初期値が設定されていない場合、クラスではイニシャライザを明示的に書く必要がありましたが、構造体においてはプロパティの値が決まっているならばイニシャライザは書く必要がありません。
インスタンスの作成
構造体もクラスと同様にインスタンス化することで、構造体内のプロパティやメソッドにアクセスすることができるようになります。
構造体のインスタンスは、その型に基づいて作成されます。各インスタンスは、構造体定義内のプロパティのコピーを持ちます。
let myCar = Car(make: "Toyota", model: "Corolla", year: 2022)
構造体のプロパティに初期値が設定されていないので、インスタンス化する際に()内でプロパティの値を指定しています。
インスタンス化された車の詳細を、構造体に定義されたdisplayDetails()メソッドを使って表示してみましょう。
myCar.displayDetails()
実行結果は以下です。
インスタンス化の際に指定したプロパティの詳細が出力されました。
Make: Toyota, Model: Corolla, Year: 2022
ちょっと待てよ、と
クラスと使い方はほぼ同じやないか、と
そんな鋭い意見をお持ちの方に、次の項目では「クラスと構造体の違い」について解説していきます!
クラス(Class)と構造体(Struct)の違い
では早速クラスと構造体の違いについて解説していきます!
違い①:参照型(クラス)と値型(構造体)の違い
クラスと構造体の主な違いは、インスタンスが参照される方法(参照型 vs 値型)にあります。
クラスのインスタンスはメモリ上で単一の存在として扱われ、そのインスタンスへの参照が共有される一方で、構造体のインスタンスはコピーされ、各インスタンスはメモリ上で独立して扱われます。
具体例を見ていきましょう!
サンプルコード
class ClassPoint {
var x: Int
var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
struct StructPoint {
var x: Int
var y: Int
}
// クラスのインスタンス生成
let classPoint1 = ClassPoint(x: 10, y: 20)
let classPoint2 = classPoint1 // classPoint1の参照をclassPoint2に代入
// 構造体のインスタンス生成
var structPoint1 = StructPoint(x: 10, y: 20)
var structPoint2 = structPoint1 // structPoint1のコピーをstructPoint2に代入
// classPoint2の値を変更する
classPoint2.x = 100
classPoint2.y = 200
// structPoint2の値を変更する
structPoint2.x = 100
structPoint2.y = 200
print("ClassPoint1: (\(classPoint1.x), \(classPoint1.y))") // 出力: ClassPoint1: (100, 200)
print("ClassPoint2: (\(classPoint2.x), \(classPoint2.y))") // 出力: ClassPoint2: (100, 200)
print("StructPoint1: (\(structPoint1.x), \(structPoint1.y))") // 出力: StructPoint1: (10, 20)
print("StructPoint2: (\(structPoint2.x), \(structPoint2.y))") // 出力: StructPoint2: (100, 200)
サンプルコードの説明
参照型(クラス): classPoint1
とclassPoint2
は同じインスタンスを参照しています。そのため、classPoint2
を通じて行った変更がclassPoint1
にも反映されています。これはクラスが参照型であるためです。
値型(構造体): 一方、structPoint1
とstructPoint2
は独立しています。structPoint2
を変更してもstructPoint1
には影響しません。これは構造体が値型であるため、structPoint1
の値がstructPoint2
にコピーされた後、それぞれが独立した存在となるためです。
違い②:メンバーワイズイニシャライザ
クラス: クラスはデフォルトでメンバーワイズイニシャライザを提供しません。明示的にイニシャライザを定義する必要があります。
構造体: 構造体は、インスタンスに必要なすべてのプロパティの初期値を決まっている場合、デフォルトのメンバーワイズイニシャライザが自動的に提供されます。これにより、コードをシンプルに保つことができます。
違い③:継承
クラス (Class): クラスは継承をサポートします。これにより、一つのクラスが別のクラスの特性を継承し、再利用し、拡張することができます。
構造体 (Struct): 構造体は継承をサポートしません。これは、構造体を使用すると、関連するデータと振る舞いを一つにまとめることができますが、継承を通じたコードの再利用はできないことを意味します。
違い④:インスタンスの破棄
クラス: クラスのインスタンスはデイニシャライザ(deinitializer)を持つことができます。これはインスタンスがメモリから解放される直前に呼び出され、リソースのクリーンアップなどの必要な後処理を行うことができます。
構造体: 構造体にはデイニシャライザがありません。構造体のインスタンスは、それを参照する最後の変数がスコープから外れた時に自動的にメモリから解放されます。
これらの特徴の違いから、書き方は同じように見えるかもしれないけど、結果が大きく変わってくるということですね!
その時のニーズに合わせて、クラスか構造体かをうまく取捨選択しましょう!
まとめ
今回は、構造体について、似た性質を持つ「クラス」との違いにスポットライトを当てて解説しました。
各々の特徴を理解して、うまく取捨選択できるようになりましょう!
この記事が皆様の開発ライフの一助になれれば幸いです!
この記事があなたのスキルアップに役立ったなら、次のキャリアステップを踏み出す絶好の機会かもしれません。エンジニアとしてのさらなる成長と挑戦を求めるなら、
未経験からIT・Webエンジニアを目指すなら【ユニゾンキャリア】
コメント
コメント一覧 (2件)
[…] 【iOS】Swiftにおける構造体(Struct)について徹底的に解説 […]
[…] あわせて読みたい 【Swift】構造体(Struct)について徹底的に解説 […]