サブスクリプト

サブスクリプトとは、配列やディクショナリの要素にアクセスする時等に使う添字式のことです。Swiftでは、構造体、列挙型、クラスにサブスクリプトによるアクセスを実装することができます。

サブスクリプトによるアクセスを実装するには、次のような内容をクラス等の定義に記述します。


class Hoge {
    :
    subscript(index: Int) -> Int {
        get {
            // 添字:indexの位置を値を返す
        }
        set(newValue) {
            // newValueを受け取る
        }
    }
}

プロパティの場合と同じように、ゲッター、セッターを記述して、受け取ったindex位置の値を返したり、新たな値を受け取ることができます。
セッターは、特に指定しなければ、newValueで受け取る値を参照できます。上の例のように、引数名を明示的に指定することも可能です。

このクラスのインスタンスに対して、次のようなアクセスが可能になります。


let hoge = Hoge()
hoge[2] = 10
print(hoge[2])

読み出しのみでセッターが不要な場合は、ゲッターのみを記述します。プロパティの場合と同様、get自体の記述も不要になります。


class Hoge {
    :
    subscript(index: Int) -> Int {
        return 〜
    }
}

また、1つのクラスに引数や戻り値の型の異なる複数のサブスクリプトを定義することもできます。呼び出されるサブスクリプトは型によって類推されます。


class Doubler {
    // 受け取った添字の値を2倍して返す。
    subscript(index: Int) -> Int {
        return index * 2
    }
    // 引数がString
    subscript(index: String) -> Int {
        return index.toInt()! * 2
    }
    // 戻り値がString
    subscript(index: Int) -> String {
        return "[\(index * 2)]"
    }
}

let doubler = Doubler()
let i1: Int = doubler[3]        // 6
let i2: Int = doubler["3"]      // 6
let s: String = doubler[3]      // "[6]"

複数の添字を使ったサブスクリプトも定義できます。


class Multiplier {
    // 2つの引数の乗算結果を返す
    subscript(val1: Int, val2: Int) -> Int {
        return val1 * val2
    }
}

let m = Multiplier()
print(m[2, 3])     // 6

次は、サブスクリプトを使ってオセロ盤の各マス目にアクセスできるようにした例です。


/* オセロのコマ */
enum Piece {
    case Black, White
}

/* オセロ盤 */
class OthelloBoard {
    class var rows: Int    { return 8 }
    class var columns: Int { return 8 }
    class var squares: Int { return rows * columns }
    var board: [Piece?]
    init() {
        board = Array(count: OthelloBoard.squares, repeatedValue: nil)
        self[3, 3] = .Black;  self[3, 4] = .White
        self[4, 3] = .White; self[4, 4] = .Black
    }
    // 指定されたマス目のコマを返す
    subscript(row: Int, column: Int) -> Piece? {
        get {
            checkSquare(row, column: column)
            return board[row * OthelloBoard.columns + column]
        }
        set {
            checkSquare(row, column: column)
            board[row * OthelloBoard.columns + column] = newValue
        }
    }
    // 位置の検証
    func checkSquare(row: Int, column: Int) {
        assert(row < OthelloBoard.rows && column < OthelloBoard.columns, "不正な位置")
    }
}

let board = OthelloBoard()
board[3, 5] = .Black