Swiftの添字付けの使い方

Swiftの添字付けの使い方をみてみます。

添字付けとは?

クラス、構造体、列挙型で定義可能な、リスト、コレクション、シークエンスのアクセスを便利にしてくれるショートカットです。
プロパティのアクセスを便利にできます。
もっと簡単にいうと配列の要素をアクセスするときの[]のこと

let tmpArray = [1, 2, 3]
print(tmpArray[0])

添字付けの文法

添字付けは以下のように書きます。

subscript(引数) -> 戻り値の型{
    get{
    添字で指定したプロパティを返す文
    }
    set (引数) {
    プロパティの値を更新する文
    }
}

set節の引数はなくてもよいです。その場合はnewValueという引数が使える。
get節は必須でset節は省略可能。set節省略で読み取り専用の添字を作れる。

添字を使ってみる

プロパティの数値桁数を添え字で指定できる構造体を作ってみます。

struct Digits {
    //保持する数値
    var number : Int = 2016
    
    //数値の桁数
    var digitAmount : Int = 0
    
    //初期化の際に数値の桁数を設定する
    init(){
        var tmpNumber = number
        
        while tmpNumber > 1{
            
            tmpNumber  = tmpNumber / 10
            digitAmount += 1
            
            
        }

    }
    
    //添字で指定した数字の桁数を取得設定できるようにする
    //1なら1桁目の数字が取れる。2なら2桁目の数字が取れる。
    subscript(index: Int) -> Int{
        get{
            //不正な数値を弾く
            guard index > 0 && index <= digitAmount else{
                return -1
            }
            
            let powNum = Int(pow(10.0,Double(index-1)))
            let digitNumber = (number / powNum) % 10
        
            return digitNumber
    
        }
        set{
            
            //不正な数値を弾く
            //indexが0より大きく、
            guard index > 0 && newValue < 10 && index <= digitAmount else{
                return
            }
            
            //各桁の数字をなんとか0にしたいな
            let digitNum = self[index]
            let powNum = Int(pow(Double(10), Double(index - 1)))
            number = number - (powNum * digitNum)
            number = number + (newValue * Int(powNum))
            
        }
    }
}

これを実行します。

var someNum = Digits()
//0桁目を調べる->不正な文字として処理
print(someNum[0])
//1桁目を調べる
print(someNum[1])
//2桁目を調べる
print(someNum[2])
//3桁目を調べる
print(someNum[3])
//4桁目を調べる
print(someNum[4])
//1桁目に9を代入
someNum[1] = 9
print(someNum.number)
//4桁目に9を代入
someNum[4] = 9
print(someNum.number)
//3桁目に8を代入
someNum[3] = 8
print(someNum.number)

実行結果は以下のとおりになります。

-1
6
1
0
2
2019
9019
9819

添字付けは2つの引数をもつこともできる

マルバツゲームのモデルを作成してみる

struct TicTacToe {
    
    //縦の列
    let rows : Int = 3
    //横の列
    let columns :Int = 3
    //各マス
    var grid : [String] {
        didSet{
            
            //マルバツゲームのマス目を出力する
            print("-----")
            
            //上段3マスを出力
            let tmpFirstArray = grid.enumerate().filter(){
                //インデックス番号が3で割ってあまりが0
                //0,1,2をまとめる
                return $0.0 / 3 == 0
            }
            for element in tmpFirstArray{
                //横並びで出力
                print(element.1, terminator:"")
            }
            print("")
            
            //中段3マスを出力
            let tmpSecondArray = grid.enumerate().filter(){
                return $0.0 / 3 == 1
            }
            
            for element in tmpSecondArray{
                print(element.1, terminator:"")
            }
            print("")
            
            //下段3マスを出力
            let tmpThirdArray = grid.enumerate().filter(){
                return $0.0 / 3 == 2
            }
            for element in tmpThirdArray{
                print(element.1, terminator:"")
            }
            print("")
        }
    }

    //初期化
    init(){
        //マス目全てに空文字を設定
        grid = Array(count: rows * columns, repeatedValue: "")
    }
    //縦と横を添字で指定
    subscript(row: Int, column: Int) -> String{
        
        get{
            //不正な数値をはじく
            //rowは0以上でrowsよりも少ない数値
            //columnは0以上でcolumnsよりも少ない数値
            guard 0 <= row && row < rows && 0 <= column && column < columns else{
                return ""
            }
            
            return grid[(row * columns) + column]
        }
        
        set{
            
            //不正な数値をはじく
            //rowは0以上でrowsよりも少ない数値
            //columnは0以上でcolumnsよりも少ない数値
            guard 0 <= row && row < rows && 0 <= column && column < columns else{
                return
            }
            
            //すでに入力されていたら、代入しない
            guard grid[(row * columns) + column].isEmpty else{
                return
            }
            grid[(row * columns) + column] = newValue
            
        }
    }
}

これを実行します。

var newGame = TicTacToe()

newGame[0, 0] = "☓"
newGame[1, 0] = "◯"
newGame[0, 1] = "☓"
newGame[1, 1] = "◯"
newGame[2, 0] = "☓"
newGame[0, 2] = "◯"
newGame[1, 2] = "☓"
newGame[2, 1] = "◯"
newGame[2, 2] = "◯"
newGame[1111, 222] = "☓"//不正な数値なので、代入されない
newGame[2, 2] = "☓" //すでに入力しているので代入されない

コンソールにはこんな感じで表示されます。


-----
☓


-----
☓
◯

-----
☓☓
◯

-----
☓☓
◯◯

-----
☓☓
◯◯
☓
-----
☓☓◯
◯◯
☓
-----
☓☓◯
◯◯☓
☓
-----
☓☓◯
◯◯☓
☓◯
-----
☓☓◯
◯◯☓
☓◯◯

以上です!