Edited at

サブスクリプションについて(Swift)


サブスクリクションとは

サブスクリクションは配列や辞書などのコレクションの要素へのアクセスを統一的に表すための文法です。


定義方法

以下が定義文になっています。

subscriptキーワードに続けて引数と戻り値の型を指定し、{}内にgetとsetでゲッタとセットを定義すればサブスクリクションの雛形の完成です。

アクセス修飾子で制限された値を参照するときのように、getで参照してsetで更新するような感じです。

subscipt(引数) -> 戻り値の値 {

 //ゲッタ
get {
return文によって値を返す処理
}
 //セッタ
set {
値を更新する処理
}
}


サンプルコード


引数一つ

//構造体定義

struct Progression {
//変数定義
var numbers: [Int]

subscript(index: Int) -> Int {
get {
return numbers[index]
}
set {
numbers[index] = newValue
}
}
}

//インスタンス化(初期化)
var progression = Progression(numbers: [1,2,3])
let element1 = progression[1]
print(element1)
//結果
2

progression[1] = 4
let element2 = progression[1]
print(element2)
//結果
4

上記のコードを見ると、構造体内で定義した変数numbersがインスタンス化時に引数を指定することで値が代入されています。

次にインスタンスprogressionに[1]を指定することで、それをsubscriptionの引数で参照し、返り値でnumbers[1]という形で返しています。その結果progressionの2番目の値の2が出力されました。その下のコードもprogression[1]に4を代入しただけで、やっていることは変わりません。

しかしまだこれでは普通に配列を参照しても簡単にできますし、必要性があまり感じられないと思います。

そこで次のコードをみてください。


引数複数

//構造体定義

struct Matrix {
 //変数定義
var row: [[Int]]

 //subscription定義(二つの引数を持っている)
subscript(row: Int, column: Int) -> Int {
get {
return rows[row][column]
}
set {
rows[row][column] = newValue
}
}
}

let matrix = Matrix(row: [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
])

let element = matrix[1, 1]
print(element)

//結果
5

上記のコードを見ると、先ほどと違いインスタンス化時に複数の配列を引数に指定して、変数rowに計3つの配列が代入されています。

次にインスタンスmatrixに[1, 1]という二つの引数を指定して代入しています。これは最初の値が先ほど代入した3つの配列の番号を表しており、次の値が配列内の値を表しています。そのため[1] == 二つ目の配列の[1] == 二つ目の値ということで、結果として5が出力されました。

つまりこのサブスクリクションを使用すると、100ある配列でも一つのインスタンスで管理ができ、とてもすっきりとしたコードが書けるということです。


セッタの省略

下記のようにサブスクリプションではセッタの省略が可能で、その場合はgetを書く必要もなく、subscription内に直接引数で参照してきた値を返す処理を書けばOKです。

struct Progression {

var numbers: [Int]

subscription(index: Int) -> Int {
return numbers[index]
}
}

var progression = Progression(numbers: [1, 2, 3])
progression[0]

//結果
1


サブスクリプションのオーバーロード

同じ値の変数(上記だとnumbers)に対して複数のサブスクリクションを指定して、引数に指定する型で区別して、一つの引数を多用的に利用することも可能です。