티스토리 뷰

728x90

서브스크립트 (Subscripts)

 

클래스, 구조체, 열거형에서 스크립트를 정의해 사용할 수 있습니다.

서브스크립트를 활용하면 추가적인 메소드 없이 특정 값을 할당하거나 가져올 수 있습니다.

 

예를들어, Array 인스턴스의 특정 요소에 someArray[index] 문법으로, 

Dictionary 인스턴스의 특정 요소에 someDictionary[key] 이런식으로 접근할수 있습니다. 

 

하나의 타입으로 여러 서브스크립트를 정의할 수 있으며, 오버로드(Overload)도 가능합니다. (질문)

또한 필요에 따라 여러 인자 값을 사용할 수 있습니다.

 


서브스크립트 문법 (Subscripts Syntax)

 

인스턴스 메소드 문법연산 프로퍼티 문법유사합니다. 

다만, 서브스크립트에선 읽기-쓰기(read-write) 또는 읽기전용이 (read only) 가능 합니다.

// 1
subscript(index: Int) -> Int {

// 2
    get {
        // 반환 값
    }
    set(newValue) {
        // set 액션
    }
}

1. subscript 키워드를 사용하여 정의를하고, 

2. gettersetter 방식을 따릅니다. 

 

연산 프로퍼티와 같이 setter에 파라미터를 따로 명시해주지 않으면 기본값으로 newValue를 사용합니다.

 

읽기전용 연산 프로퍼티 같이,  get, set을 키워드를 사용하지 않음으로써 간단하게 getter (읽기전용) 서브스크립트를 정의할 수 있습니다. 

subscript(index: Int) -> Int {
  // 반환 값
}

 

다음은 읽기전용 서브스크립트의 예제 입니다.

struct TimeTable {
    let multiplier: Int
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}
let threeTimesTable = TimeTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
// six times three is 18

multiplier를 3으로 받는 TimeTable구조체를 인스턴스화 한  threeTimesTable에 [6] 이라는 인덱스(index)를 넣어줌으로써,

subscript 구문에 index = 6, multiplier = 3 을 넣어줌으로써, 둘을 곱한 값 18이 출력 됩니다.

 

 


서브스크립트 사용 (Subscripts Usage)

 

'subscript' 는 사용되는 문맥에 따라 달라집니다.

일반적으로 collection, list, sequence의 멤버 요소에 쉽게 액세스하기 위한 용도로 사용됩니다.

 

Swift의 사전(Dictionary) 타입에서 서브스크립트의 사용 예제를 봅시다.

var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2

print(numberOfLegs) 
// ["cat": 4, "ant": 6, "spider": 8, "bird": 2]

numberOfLegs는 타입추론에 의해 [String: Int] 타입을 갖고,

두번째 줄 numberOfLegs["bird"] = 2  numberOfLegs의 key 값에 "bird", value 값에 2  를 넣습니다.

 

NOTE

사전(Dictionary) 타입은 모든 key에 값이 없을 수도 있다는 사실을 모델링하고,
key에 nil 값을 할당하여 key에 대한 값을 삭제할 수 있는 방법을 제공합니다.

 

서브스크립트 옵션 (Subscripts Options) 

 

서브스크립트는 파라미터에 어떤 숫자던, 어떤 타입이던, 어떤 반환 값이던 제한이 없습니다.

함수와 다른점은 in-out 파라미터를 사용할 수 없습니다.

 

서브스크립트는 단일 파라미터를 사용하는 것이 일반적이지만 타입에 적합한 경우 여러 파라미터를 사용할 수도 있습니다.

 

아래는 서브스크립트를 이용한 다차원 행렬을 선언하고 접근하는 예제 입니다.

struct Matrix {
    let rows: Int, columns: Int
    var grid: [Double]
    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        grid = Array(repeating: 0, count: rows * columns)
    }
    func indexIsValid(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    subscript(row: Int, column: Int) -> Double {
        get {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}

 

구조체 Matrix는 rows와 columns 두개의 파라미터를 받으며,  Double 타입의 rows * columns 값을 저장할 수 있을 만큼 충분히 큰 배열을 만듭니다.

행렬의 각 포지션에는 초기값 0.0 이 지정됩니다. 

 

아래와 같이 초기값을 지정해 보겠습니다.

var matrix = Matirx(rows: 2, columns: 2)

 

rows: 2, columns: 2를 갖는 새로운 Matrix인스턴스를 만들어서 단조롭게 된 버전의 matrix 입니다.

 

matrix 내부의 값을 서브스크립트로 콤마 ( , )를 이용해 row와 column 값을 넣어줄 수 있습니다.

matrix[0, 1] = 1.5    // 0번째 row, 1번째 column에 1.5를 넣음

matrix[1, 0] = 3.2    // 1번째 row, 0번째 column에 3.2를 넣음

즉 아래와 같이 입력이 됩니다.

 

 

행렬의 입출력시 row/column의 범위가 적절한지는 indexIsValid(row,column) 메소드에서 확인합니다.

func indexIsValid(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }

 

만약 적절한 범위를 벗어나면 assertion(assert)이 실행됩니다.

let someValue = matrix[2, 2]

// 위의 matirx의 사용범위는 [1, 1] 까지
// [2, 2]가 사용할 수 있는 행렬의 범위를 벗어나므로 assert가 실행됨

 

 

타입 서브스크립트 (Type Subscripts) 

 

서브스크립트 자체에 타입을 지정할 수 있는데 이를 타입 서브스크립트 라고 합니다.

static 키워드를 사용하여 타입 서브스크립트라는걸 나타낼 수 있고, 

클래스에선 class 키워드를 사용하여 하위클래스가 상위 클래스를 상속받아 override(재정의)할 수 있습니다. 

 

아래는 타입 서브스크립트이 예제 입니다.

enum Planet: Int {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
    static subscript(n: Int) -> Planet {  // static 키워드 사용 (타입 서브스크립트)
        return Planet(rawValue: n)!
    }
}
let mars = Planet[4]
print(Planet[2])
print(mars)

 

static 을 사용하여 타입 서브스크립트인걸 알 수 있으며,

인스턴스를 만들 필요없이 바로 Planet[4]에 접근하여 상수 mars에 값을 넣어준걸 확인할 수 있습니다. 


오늘은 서브스크립트에 대해 알아보았는데요.

아직까지는 어디에 써야 적합할지 짐작이 가질 않네요 ㅠ 

일단 이런게 있구나 정도로만 이해를 하고 넘어가고 

추후 여러 코드들을 보면서 좋은 예제가 있다면 추가 포스팅 하겠습니다 :) 

728x90