본문 바로가기

카테고리 없음

Subscripts

클래스, 구조체, 열거형은 콜렉션, 리스트, 시퀀스 멤버의 요소에 접근할 수 있는 단축키인 서브 스크립트를 정의할 수 있습니다.

설정과 검색을 위한 별도의 메서드 없이 인덱스로 값을 설정하고 조회하기 위해 서브 스크립트를 사용합니다.

서브 스크립트는 평소에도 많이 사용하고 있습니다. 배열과 딕셔너리에서 많이 사용하고 있었는데

someArray[index] 처럼 대괄호 안에 index를 전달해서 Array의 요소에 접근하고

someDictionary[key] 처럼 배열의 특정 key의 value에 접근하기위해 대괄호 안에 key값을 이용하여 요소에 접근하는 방법이 있습니다.

 

단일 타입을 위한 여러개의 서브 스크립트를 정의할 수 있고 적절한 서브스크립트 오버로드는 서브스크립트에 전달하는 인덱스 값의 유형에 따라 선택됩니다. 서브 스크립트는 단일 차원으로 제한되지 않고 사용자 정의 타입의 요구에 맞게 여러개의 입력 파라미터로 서브스크립트를 정의할 수 있습니다.

 

Subscript Syntax

서브 스크립트를 사용하면 인스턴스 이름 뒤의 대괄호에 하나 이상의 값을 작성하여 타입의 인스턴스를 조회할 수 있습니다.

인스턴스 메서드 구문과 계산 프로퍼티 구문과 유사합니다.

인스턴스 메서드와 다르게 서브 스크립트는 읽기-쓰기 또는 읽기 전용이 될 수 있고 계산 프로퍼티와 같게 getter, setter를 통해 동작합니다.

subscript(index: Int) -> Int {
    get {
        // Return an appropriate subscript value here.
    }
    set(newValue) {
        // Perform a suitable setting action here.
    }
}

newValue의 타입은 서브 스크립트의 반환 값과 동일합니다.

계산 프로퍼티와 마찬가지로 setter의 newValue 파라미터를 지정하지 않으면 newValue가 기본 파라미터로 제공됩니다.

 

읽기전용 계산 프로퍼티와 마찬가지로 get 키워드와 중괄호를 삭제하여 읽기 전용 서브 스크립트를 선언할 수 있습니다.

subscript(index: Int) -> Int {
    // Return an appropriate subscript value here.
}

 

다음 코드는 Int형 n-times-table을 표시하기 위한 TimesTable 구조체의 읽기 전용 서브스크립트 정의입니다.

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

threeTimsTable은 TimesTable의 3배 테이블을 표시하기 위해 생성되고, 인스턴스의 multipler 파라미터를 사용하는 값으로 구조체 initializer에 3의 값을 전달합니다.

 

Subscript Usage

서브 스크립트의 정확한 의미는 사용되는 컨텍스트에 따라 다릅니다. 일반적으로 서브 스크립트는 콜렉션, 리스트, 시퀀스의 멤버 요소에 접근하는 바로가기로 사용됩니다. 특정 클래스 또는 구조체의 기능에 가장 적합한 방식으로 서브 스크립트를 자유롭게 구현할 수 있습니다.

Context?
간단하게 컨텐츠를 담은 그 무언가 예를들어 물컵에 물이 담겨 있다면 물은 “컨텐츠” 물컵은 “컨텍스트” 모나드, 함수객체, 컨텍스트에 대한 차이에 대해 추가로 정리할 필요가 있음

 

예를들어 Swift의 Dictionary 타입은 인스턴스에 저장된 값을 설정하고 조회하기 위해 서브 스크립트를 사용합니다.

서브 스크립트 대괄호 내에 딕셔너리의 키를 제공하고 서브 스크립트르 통해 딕셔너리의 값을 설정할 수 있습니다.

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

 

위 예제에서 numberOfLegs 라는 [String: Int] 타입의 변수를 선언하고 “bird” 라는 키를 제공하고 딕셔너리의 서브 스크립트를 이용하여 Int형 2라는 값을 할당합니다.

Note
Swift의 Dictionary 타입은 옵셔널 타입을 반환하는 서브 스크립트인 key-value 서브 스크립트를 가지고 있습니다. 위의 numberOfLegs 딕셔너리에서 key-value 서브 스크립트는 옵셔널 Int 값을 반환합니다.

 

Subscript 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.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는 initializer는 2개의 파라미터 rows와 columns 를 호출하고 Double 타입의 rows * columns 값을 저장하는 충분히 큰 배열을 생성합니다.

행렬의 각 위치는 0.0 으로 초기값이 주어집니다.

적절한 행과 열의 수를 초기화로 전달하여 새로운 Matrix 인스턴스를 생성할 수 있습니다.

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

 

2행과 2열을 가지는 새로운 Matrix 인스턴스를 생성합니다. Matrix 인스턴스의 grid 배열은 왼쪽 상단에서 오른쪽 하단으로 읽는 것처럼 행렬의 평변화 버전입니다.

 

행렬의 값은 콤마로 구분된 서브 스크립트에 행과 열 값을 전달하여 설정할 수 있습니다.

matrix[0, 1] = 1.5
matrix[1, 0] = 3.2

 

위 2개의 구문은 행렬의 우측 상단에 1.5 값을 좌측 하단에 3.2 값을 설정하기 위해 서브 스크립트의 setter를 호출합니다.

 

 

Matrix 서브 스크립트에 getter와 setter 둘다 서브 스크립트의 row와 column 값이 유효한지 판단하기 위해 assertion이 포함됩니다. Matrix는 요청한 row와 column이 행렬의 범위 안에 있는지 판단하기 위해 indexIsValid(row:colum:) 메서드를 포함합니다.

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

 

assertion은 행렬 범위를 넘어 서브 스크립트에 접근하려고 하면 에러가 발생합니다.

let someValue = matrix[2, 2]
// This triggers an assert, because [2, 2] is outside of the matrix bounds.

 

Type Subscripts

인스턴스 서브 스크립트는 특정 타입의 인스턴스를 호출하는 서브 스크립트 입니다. 타입 자체에서 호출되는 서브 스크립트도 정의 할 수 있는데 이런 서브 스크립트를 타입 서브스크립트라고 합니다. subscript 키워드 앞에 static을 붙여 타입 서브스크립트를 나타냅니다. 클래스는 하위 클래스에서 수퍼 클래스의 서브스크립트를 재정의 할 수 있게 하기 위해 static 대신 class 키워드를 사용할 수 있습니다.