【Swift入門】extensionとは?使い方を理解しよう

こんにちは。ライターの亀田です。

2014年に突如発表されたアップルの新プログラミング言語であるSwift(※)は、瞬く間に受け入れられました。

理由はいくつかありますが、それまでアップル社の製品の主要なプログラミング言語であったObjective-Cに比べ、斬新な機能がいくつもありました。

その中の一つに、今回紹介するextensionがあります。

ここでは、

・extensionとは何か
・extensionがSwiftプログラミングを快適にする理由

で、extensionの概念そのものを説明します。さらに、

・extensionの具体的使用例

で、実際にさまざまなサンプルを通して、extensionの使い方を紹介します。

※この記事ではSwift3.1を使用しています。

目次

extensionとは何か

extensionとは、拡張するという意味であり、

・クラス
・構造体
・列挙型

に対して機能を拡張できます。書式は以下のとおりになります。

extension (拡張するものの名前){
  // 追加メソッド・プロパティなどを定義
}

Objective-Cに詳しい方なら、これがこの言語で用いられるカテゴリと同じものだと思われるかもしれません。

たしかに基本は同じなのですが、Swift ではInt や Double などのプリミティブな型でもextension で拡張することができます

その点が最大の違いといえます。

継承の概念との違い

同時にクラスを拡張するという意味では、継承の概念とも似ています。

しかし、継承の場合は、あるクラスの機能を拡張するのに別なクラスを用意する必要があります。

それに対し、extensionはすでにあるクラスを動的に拡張することができるのです。

また、継承の場合は、既存のメソッドを上書きするオーバーライドの概念がありますが、extensionにはそれがありません。

つまり、extensionではもともとある機能の変更はできないのです。

extensionの記述例

では、具体的な記述例を見て見ましょう。

たとえば、以下のようなクラスがあったとします。

// パーソン
struct Person {
    let name: String        // 名前
    var age: Int            // 年齢
}

この構造体を以下のようにしてインスタンスを生成します。

let taro = Person(name: "山田太郎", age: 35)

このままでは何のメソッドもありません。そこで

extension Person{
 func show(){
  print(self.name,":",self.age)
 }
}

とすると、ここにshow()というメソッドが追加されます。これにより

taro.show()

とすると、

山田太郎:35

のような結果が出力されます。

これがextensionの基本的な使い方の一例です。

extensionがSwiftプログラミングを快適にする理由

前述のように、Swiftのextensionの概念はObjective-Cのカテゴリを拡張したものだということはすでに説明したとおりです。

違いはそれだけではありません。

そもそもカテゴリとは、既存のクラスにメソッドを追加するというのが目的であったのに対し、extensionでは、以下のような機能の拡張が可能です。

・計算プロパティ(クラス、構造体に対して)
・タイププロパティ
・メソッド
・subscript
・イニシャライザ(初期化子)
・ネストされた型
・ プロトコルに対する準拠

つまり、カテゴリよりもずっと強力な機能だということがわかります。

extensionの具体的使用例

前述のようにカテゴリと比べてextensionはかなり強力な概念だということがわかりました。

最後に、それらを実際に利用したextensionを用いた実際の簡単な実例を紹介しましょう。

データ型の拡張と範囲検出

まずは、基本的なデータ型のクラスの一つである、Intにextensionを導入した実例を見てみましょう。

extension Int {
    static var zero: Int { return 0 }
    mutating func inverse() {
        self = -self
    }
}
// Intのzeroプロパティを表示する
print(Int.zero)
// nに3を代入し、符号を逆転させる
var n = 3;
n.inverse();
print(n);

実行結果

0
-3

Intはもともと存在する整数を表すクラスですが、このように簡単にプロパティやメソッドを追加できます。

zeroプロパティでは、値が0のIntを取得できます。

また、inverse()メソッドを呼ぶことにより、符号を逆転することが可能です。

値型に対して自分自身や付随するプロパティを変更する場合、mutatingをメソッドに付けます。

これにより、自身の符号を逆転することができます。

クラスの拡張と初期化子

次に、クラスを拡張して、イニシャライザ(初期化子)を導入してみることにします。

struct Person {
    var name: String
    init?(_ name: String) {
        self.name = name
    }
}

var p = Person("Tom")
print(p!.name)
Tom

init?()の部分がイニシャライザです。この概念はクラスのコンストラクタの概念に似ています

最大の特徴はこのようにクラスに後付けできることにあります。

subscriptの記述例

subscriptとは、配列などの添え字の意味です。

extendにより新たに配列と添え字の機能を追加することもできます。

import Foundation

extension Double {
    subscript(digitIndex: Int) -> Int {
        let digitBase = pow(10.0, Double(digitIndex))
        return Int(self / digitBase) % 10
    }
}
print(1234.01234[0] )
print(1234.01234[2] )
print(1234.01234[-2] )
4
2
1

ネストの記述例

最後にネストを紹介します。これはextensionの入れ子構造のことです。

extension Double {
    enum Sign {
        case Plus
        case Zero
        case Minus
    }
    var sign: Sign {
        if self > 0 {
            return .Plus
        } else if self < 0 {
            return .Minus
        } else {
            return .Zero
        }
    }
}

print((5.1).sign)
print((-2.1).sign)
print((0.0).sign)
Plus
Minus
Zero

まとめ

以上のように、Swiftにはextensionという大変強力な機能について以下のような流れで説明してきました。

・extensionとは何か
・extensionがSwiftプログラミングを快適にする理由
・extensionの具体的使用例

Swiftにはこのほかにも、Objective-Cにもともとあった機能を拡張してさらに強力にした機能がたくさんあります。

そしてそれらの機能は現在でも進化を続けています

さらに機能は便利なだけではなく上手に活用すればより美しいソースコードを書くことが可能です。

この記事に興味をもたれたら方はそのような機能についても学習してみることをお勧めします。

この記事を書いた人

エンジニアとして独自の製品やサービスを開発する傍ら、エンジニア教育にも力を入れています。企業研修や専門学校での非常勤講師もしながら、独自の言語学習サイト「一週間でわかるシリーズ」を運営し、エンジニアになりた人をサポートする活動をライフワークにしています。
【一週間で学べるシリーズ】
http://sevendays-study.com/

目次