Swiftのクラスと構造体の比較

クラスと構造体(Classes and Structures)

ここでは、クラスと構造体を比較して、共通の特性は何か?、違いは何か?について説明します。その後に具体例を交えて、クラスと構造体の定義構文、インスタンスとは何か?、プロパティへのアクセス、さらに構造体のmemberwise initializerについて説明します。

クラスと構造体、共通の特性

Swiftではクラス(Classes)と構造体(Structures)にほとんど違いがありません。公式マニュアルにもあるクラスと構造体で実装できる機能を見ると、Swiftにおける構造体はかなり多機能であることが分かります。

最後の2つはクラスや構造体が保有する特性ではありません。これらはクラスや構造体の機能をより拡張するためのツールになります。

クラスと構造体の違い

ではクラスと構造体の違いは何か?というのは素朴な疑問になります。決定的な違いは

クラスは参照型、構造体は値型

です。これは後で詳しく紹介します。基本的にはクラスの方が多機能で、以下に列挙した機能はクラスだけに実装されています。

これらの特性は「Swiftをもっと深く学ぶ」で詳しく説明しています。

定義構文(Defining Syntax)| クラスと構造体をどう定義するか?

クラスと構造体の定義構文

クラスと構造体の定義は、基本的には以下のような構文になります。

// クラスの定義
class ClassName
{
    // Class definition
}

// 構造体の定義
struct StructureName
{
    // Structure definition
}

クラスにはclassキーワード、構造体にはstructキーワードを付けます。また、名前はClassNameのように大文字から始めます。クラスや構造体が保有するプロパティやメソッドは波括弧(curly brackets){}の中に書きます。

プロパティとは変数や定数のようなもので、メソッドとは関数のようなものです。どちらも独自型(クラスや構造体、列挙型)内部で定義された場合の呼び名になります。

クラスと構造体の定義 | 掃除機クラスの例

早速実際のクラスや構造体を作ってみます。ここでは掃除機をクラスとして定義してみます。

// 掃除機クラス
// 電源(電池)
struct Battery {
    var power   = 0.0 // V、ボルト
    var useTime = 0 // 分
}
// 掃除機本体
class Cleaner {
    // 掃除機のスペック
    var battery = Battery()
    var name: String?
    var height = 0 // mm
    var width  = 0 // mm
    var weight = 0.0 // kg
    // ゴミ
    var dust = 0
    // 吸引
    func vacuum() {
        dust += 1
    }
}

外付けバッテリーを持つコードレスクリーナーのイメージです。

先ず電源であるバッテリーBatteryは構造体で定義されています。バッテリーは2つのプロパティpoweruseTimeを持っています。power0.0useTime0で初期化されています。したがって、これらの変数の型はそれぞれDoubleIntで型推論(type inference)されています

本体である掃除機はクラスCleanerになっています。このクラスは5つのプロパティ変数を使って、掃除機のスペックを表現しています。また、ゴミとしてdust変数、吸引機能はvacuum()メソッドで実装しています。

掃除機の持つバッテリーは、先ほど定義した構造体Batteryを使って生成しています。

var battery = Battery()

掃除機の名前は任意ということを表現しているのでoptionalsString?)になっています。また、大きさや重さを表すのに3つの変数を使っています。これだと2次元掃除機になってしまいますが、ひとまず高さheight(掃除機の長さ)と幅width(正面から見た場合の横の長さ)だけを与えておきます。

Swiftの基本的な型は構造体

このように、クラスや構造体は自作の新しいSwift型を定義していることになります。すでに気づいている方もいるかもしれませんが、Swiftの基本型であるIntStringなどは、実は全て構造体です。

参考:Int Structure Reference
https://developer.apple.com/reference/swift/int

インスタンス(Instances)って何?

先ほど作った掃除機クラスCleanerとバッテリー構造体Batteryは、クラスや構造体の実体ではありません。クラス・構造体定義構文は、いわば設計図(または仕様)のようなものです。掃除機なので説明書と言った方が分かりやすいかもしれません。

プログラム上での掃除機本体が、まさにインスタンス(Instances)と呼ばれるものです。つまり、インスタンスとはクラス(または構造体)の実体になります。

インスタンスを生成するには次のように書きます。

// クラス、構造体のインスタンス
let someBattery = Battery()
let someCleaner = Cleaner()

実は、掃除機クラスの中で、すでに構造体Batteryのインスタンスを生成しています。上記の例は、インスタンス生成の最も単純な形になっていて、クラス名(構造体名)の直後に空のかっこ()を付けます。このクラス(構造体)初期化構文の場合、クラス等が保有しているプロパティは全てデフォルト値で初期化されます。

プロパティ(Properties)へのアクセス

クラスや構造体のプロパティ(変数や定数など)にアクセスするにはdot syntaxを使います。名前は難しそうですが、単にインスタンスの直後にピリオド.をつけて、プロパティ名を指定するだけです。

// プロパティへのアクセス
print("バッテリーの電圧は\(someBattery.power)Vです")

// サブプロパティへのアクセス
print("掃除機のバッテリー電圧は\(someCleaner.battery.power)Vです")

上記の例のように、インスタンス名.プロパティで、クラスや構造体のプロパティにアクセスします。また、2番目の例では、Cleanerクラスが持っているbatteryインスタンスのプロパティにアクセスしています。

プロパティが変数であれば、新しい値を代入することも可能です。

// プロパティ変数へ値の代入
someCleaner.battery.power = 10.8
print("掃除機のバッテリー電圧は\(someCleaner.battery.power)Vです")

構造体のMemberwise Initializer

構造体では自動的にMemberwise Initializerという機能が実装されます。Member(メンバー、メンバ?)は、クラスや構造体内のプロパティを指す場合に良く使われる言葉です。したがって、memberwise initializerは「メンバー(プロパティ)全部の初期化機能」と訳せます。

以下のサンプルプログラムは、memberwise initializerの使用例です。

// 構造体のメンバーを初期化
let makitaBattery1 = Battery(power:10.8, useTime:12)
print("バッテリーの電圧は\(makitaBattery1.power)Vで 、連続稼働時間は\(makitaBattery1.useTime)分です")
//"バッテリーの電圧は10.8Vで 、連続稼働時間は12分です"と表示

関数のパラメータを指定するのに似ていますね。カッコの中にプロパティ名: を列挙して初期化します。

ただし、memberwise initializerを使って初期化する場合は

  • 構造体が保有する全てのプロパティを列挙して初期化する
  • 定義したプロパティの順番を守る

というルールがあります。例えば、プロパティの順番を入れ替えて初期化しようとすると、

// 定義どおりの順番でないとダメ
let makitaBattery2 = Battery(useTime:12, power:10.8)
// コンパイルエラー: error: argument 'power' must precede argument 'useTime'

このように怒られてしまいます。

まとめ

  • クラスと構造体、プロパティ・メソッドのカプセル化という観点では違いがない。クラスの方が多機能
  • クラスはclassキーワード、構造体はstructキーワードで定義
  • Swiftの基本型(Intなど)は構造体
  • クラス(構造体)定義は設計図であって実体じゃない。プログラム上での実体はインスタンス(instances)
  • 構造体のmemberwise initializerでは、保有している全てのプロパティを宣言通りに初期化しなければならない

掃除機クラスの参考にしたサイト

掃除機クラスを考える際に参考にしたサイトです。

マキタ コードレスクリーナーの選び方
http://makita-cleaner.com/makita-cordless-cleaner/

日立工機コードレスクリーナ
http://www.hitachi-koki.co.jp/powertools/pro/blower/r14dsal/r14dsal.html

日立工機のコードレスクリーナーを徹底調査
http://makita-cleaner.com/hitachi-koki-cordless-cleaner/