Swift & Objective-C

Swiftのクラス(class)と構造体(struct)の違いを総整理(値型・参照型)

Swiftで開発していると、誰もが一度は手を止める瞬間に出会います。

読了 4 分
Swiftのクラス(class)と構造体(struct)の違いを総整理(値型・参照型)のカバー画像

Swiftで開発していると、誰もが一度は手を止める瞬間に出会います。

「これはclassにするべき? それともstruct?」

私もSwiftを学び始めた頃は、なんとなくこの2つを選んでいました。奇妙なバグに遭遇して初めて、違いをきちんと勉強したのです。

まず結論からお話しします。

特別な理由がなければ、まず構造体(struct)を選びましょう。

クラスを使うのは、「共有される1つの状態」が本当に必要なときだけです。

Appleの公式ガイドラインも同じ考え方です。今日はその理由を順に説明します。


まず押さえたいポイント(3つ)

忙しい方のために、先にまとめます。

  1. 構造体は値型です。コピーすると完全に別の値になります。
  2. クラスは参照型です。コピーしても同じインスタンスを指します。
  3. 迷ったらまずはstruct、継承や共有状態が必要なときだけclassです。

この3行だけ覚えておけば、半分は終わりです。


値型と参照型は何が違う?

言葉だけでは分かりにくいですよね。コードで見るのが一番早い方法です。

まずは構造体です。コピーした瞬間、それぞれ独立した存在になります。

struct Point { var x = 0 }

var a = Point()
var b = a      // 値がコピーされた
b.x = 10

print(a.x, b.x)
// 出力: 0 10

bを変更しても、aはそのままです。それぞれが自分の値を持っているからです。

次はクラスです。同じようなコードに見えますが、結果は異なります。

class Box { var x = 0 }

let a = Box()
let b = a      // 参照がコピーされた(同じオブジェクト)
b.x = 10

print(a.x, b.x)
// 出力: 10 10

bだけを変更したのに、aまで10になりました。

2つが同じインスタンスを指しているからです。私を悩ませたバグは、まさにこれでした。

コピーか共有か。矢印を見るだけで違いが分かります。
コピーか共有か。矢印を見るだけで違いが分かります。

では、いつ何を使う?(選択基準)

実務で判断するとき、私はこの表を頭に思い浮かべます。

状況 判断
単純にデータを保持するモデル 構造体
コピー後も互いに独立していてほしい 構造体
継承が必須 クラス
複数の場所で同じインスタンスを共有 クラス
Objective-Cとの連携が必要 クラス

もう少し具体的に整理すると、次のようになります。

  • 座標、色、サイズのように値そのものを表すなら、構造体が自然です。
  • 画面コントローラやネットワークマネージャのように、1つの状態を複数箇所で共有して見る必要があるなら、クラスが適しています。
  • AppleのSwiftUIがViewをstructにしているのも同じ理由です。軽量で予測しやすいからです。

ちなみにSwift標準ライブラリのArrayStringDictionaryはすべて構造体です。それほど値型が基本だということです。

私はいつも、まずこの質問を投げかけてから始めます。
私はいつも、まずこの質問を投げかけてから始めます。

構造体を先に勧める理由

値型は予測しやすいものです。

渡した値が別の場所でこっそり変更される心配がありません。関数に渡しても、元の値は安全です。

マルチスレッド環境でも安心です。共有状態がないため、データ競合が減るからです。

一方、クラスは強力ですが慎重さが必要です。同じインスタンスをあちこちで保持すると、どこで値が変わったのか追跡しにくくなります。

だから「基本はstruct、必要なときだけclass」という習慣が、バグを大きく減らしてくれます。


いつ使い、いつ避けるべきか

最後に、判断基準を短くまとめます。

  • 構造体を使う:データ中心のモデル、独立したコピーが必要な場合、スレッドセーフが重要な場合
  • クラスを使う:継承が必要な場合、1つのインスタンスを共有する場合、識別子(identity)に意味がある場合
  • 避ける:単純なモデルに慣習でclassを使うこと、共有が必要なのにstructで無理に代用すること

面接ではこう聞かれます

Q. 構造体とクラスの最大の違いは何ですか?

構造体は値型、クラスは参照型です。構造体はコピーすると完全に独立した値になりますが、クラスはコピーしても同じインスタンスを指します。また、継承とdeinitを使えるのはクラスだけです。

Q. Swiftはなぜ構造体の使用を推奨するのですか?

値型には共有状態がないため、副作用が少なく予測しやすいからです。元の値が意図せず変更される危険がなく、マルチスレッド環境でも安全なので、バグの削減に役立ちます。


最初は単なる文法の違いだと思っていましたが、掘り下げるほど設計の問題だと分かりました。

今日この基準を身につけておけば、次のプロジェクトから迷いが減るはずです。値か共有か、まずこの問いを投げかけてみてください。

あわせて読みたい