Subscripts

Swift/Language Guide 2018.08.30 22:23

[최종 수정일 : 2018.08.29]

원문 : 애플 개발 문서 Swift 4.2 Language Guide - Subscripts

서브스크립트(Subscripts)

클래스, 구조체, 열거형은 컬렉션(collection), 리스트(list), 시퀀스(sequence)의 멤버요소에 간단하게(shortcuts) 접근하는 서브스크립트(subscripts)를 정의할수 있습니다. 설정하거나 가져오는 별개의 메소드 없이 인덱스(index)로 값을 설정하거나 가져오기 위해 서브스크립트를 사용합니다. 예를들어, someArray[index]와 같은 Array 인스턴스에 있는 요소들과 someDictionary[key]와 같은 Dictionary 인스턴스에 있는 요소들에 접근합니다.

단일 타입에 대해 여러개의 서브스크립트를 정의할 수 있고, 서브스크립테에 전달하는 인덱스의 타입에 따라 적절한 서브스크립트가 오버로드(overload)하여 선택됩니다. 서브스크립트(Subscripts)는 단일 차원(dimension)으로 제한되지 않고, 사용자정의 타입의 요구사항에 따라 여러개의 입력 매개변수로 서브스크립트를 정의 할수 있습니다.

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

서브스크립트는 인스턴스 이름 뒤에 대괄호(square brackets []) 하나 이상의 값들을 작성해서, 타입의 인스턴스를 조회하는 것이 가능합니다. 이러한 문법은 인스턴스 메소드 문법과 계산 프로퍼티 문법과 비슷합니다. subscript 키워드를 작성하여 서브스크립트를 정의하고, 하나 이상의 입력 매개변수와 반환 타입을 지정합니다. 인스턴스 메소드와 다르게, 서브스크립트는 읽기-쓰기(read-write) 또는 읽기 전용(read-only)이 가능합니다. 이 동작은 계산 프로퍼티와 같은 방법으로 getter와 setter를 이용하게 됩니다.

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

newValue의 타입은 서브스크립트의 반환 타입과 같습니다. 계산 프로퍼티 처럼, setter의 (newValue) 매개변수를 지정하지 않도록 선택할수 있습니다. 여러분이 직접 제공하지 않은 경우에, setter에 기본 매개변수 newValue가 제공됩니다.

읽기전용(read-only) 계산 프로퍼티처럼, get 키워드와 중괄호를 제거해서, 읽기전용(read-only) 서브스크립트 선언을 단순하게 할 수 있습니다.

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

다음 예제는 정수형 n단(n-times-table)을 표현하기 위해 TimesTable 구조체를 정의한 읽기전용(read-only) 서브스크립트를 구현한 것입니다.

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"

이 예제에서, TimesTable의 새로운 인스턴스는 3단(three-times-table)을 표현하기 위해 생성됩니다.이것은 인스턴스의 multiplier 매개변수에 사용하는 값으로 구조체의 초기화(initializer)에 값 3을 전달하는 것을 나타냅니다.

threeTimesTable[6]를 호출에서 볼수 있는 것처럼, 서브스크립트를 호출해서 threeTimesTable 인스턴스를 조회할수 있습니다. 이것은 값 18을 반환하는 3단(three-times-table)에서 6번째 항목을 요청합니다.

주의
n단(n-times-talbe)은 고정된 수학공식을 기반으로 합니다. threeTimesTable[someIndex]에 새로운 값을 설정하는 것은 적절하지 않고, TimeTable에 대한 서브스크립트는 읽기전용(read-only) 서브스크립트로 정의됩니다.

서브스크립트 사용법(Subscript Usage)

서브스크립트(subscript)의 정확한 의미는 사용되는 컨텍스트(context)에 따라 결정됩니다. 서브스크립트는 일반적으로 컬렉션, 리스트, 시퀀스 에서 멤버 요소들에 접근하는 쉬운방법(shortcut)으로 사용됩니다. 특정 클래스나 구조체의 기능과 가장 잘 어울리는 방법으로 서브스크립트를 자유롭게 구현합니다.

예를들어, Swift의 Dictionary 타입은 Dictionary 인스턴스에 있는 저장소에 값을 설정하고 가져오기 위해 서브스크립트를 구현합니다. 서브스크립트 대괄호(brackets []) 안에 딕셔너리의 키 타입의 키(key)를 딕셔너리에 값을 설정 할 수 있고, 서브스크립트에 딕셔너리의 값 타입의 값을 할당 할 수 있습니다.

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

위의 예제는 numberOfLegs변수를 정의하고 3개의 key-value 쌍을 포함한 리터럴(literal) 딕셔너리로 초기화 하였습니다. numberOfLegs 딕셔너리의 타입은 [String: Int]로 추론됩니다. 딕셔너리를 생성하고 난 후에, 이 예제는 딕셔너리에 "bird"라는 String 키와 Int인 2의 값을 추가하기 위해 서브스크립트 할당을 사용합니다.

Dictionary 서브스크립트에 대한 자세한 정보는 딕셔너리 사용과 수정하기(Accessing and Modifying a Dictionary)를 보세요.

주의
Swift의 Dictionary 타입 구현은 서브스크립트로 가져오고 옵셔널(optional) 타입을 반환하는 key-value 서브스크립트입니다. 위의 numberOfLegs 딕셔너리에 대해, key-value 서브스크립트는 Int? 또는 "옵셔널(optional) int" 타입을 가져오고 반환합니다. Dictionary 타입은 모든 키가 값을 가져오지는 않을 것이라는 것을 모델링하고, 키에 대한 값을 제거하는 방법으로는 키에 nil을 할당하기 위해, 옵셔널 서브스크립트 타입을 사용합니다.

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

서브스크립트는 임의의 입력 매개변수의 개수를 가질수 있고, 이러한 입력 매개변수는 어떤 타입도 될수 있습니다. 서브스크립트는 어떤 타입이든 반환할수 있습니다. 서브스크립트는 가변 매개변수를 사용할수 있지만, in-out 매개변수를 사용하거나 기본 매개변수 값을 제공할 수는 없습니다.

클래스나 구조체는 필요한 경우에 많은 서브스크립트 구현을 제공할 수 있고, 값의 타입이나 서브스크립트가 사용되는 시점에 서브스크립트 대괄호 포함된 값들을 기반으로 추론되어 적절한 서브스크립트가 사용될 것입니다. 여러개의 서브스크립트를 정의하는 것을 서브스크립트 오버로딩(subscript overloading)이라고 합니다.

서브스크립트에 단일 매개변수를 가져오는 것이 가장 일반적이지만, 타입에 맞게 여러개의 매개변수로 서브스크립트를 정의할 수 있습니다. 다음 예제는 Double 값의 2차원 행렬(two-dimensional matrix)을 표현하는 Matrix구조체를 정의한 것입니다. Matrix 구조체의 서브스크립트는 2개의 정수 매개변수를 가져옵니다.

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는 2개의 매개변수 rows와 columns 를 받는 초기화를 제공하고, Double 타입의 rows * columns 값을 저장할 수 있는 크기의 배열을 생성합니다. 행렬에서 각 위치에 초기값 0.0을 넣습니다. 이를 위해, 정확한 크키의 새로운 배열을 생성하고 초기값을 생성하기 위해, 배열의 크기와 초기값 0.0을 배열의 초기화에 전달합니다. 이 초기화는 기본 값으로 배열 생성하기(Creating an Array with a Default Value)에서 더 자세히 설명되어 있습니다.

초기화에 적절한 행과 열 갯수를 전달해서, 새로운 Matrix 인스턴스를 구성할 수 있습니다.

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

위의 예제에서, 2개의 행(rows)과 2개의 열(columns)로 새로운 Matrix 인스턴스를 생성하였습니다. Matrix 인스턴스에 대한 grid 배열은 왼족 위에서 오른족 아래로 읽는 것과 같이, 행렬을 실제로 평면화시킨 버젼입니다.

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

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

이러한 두개의 문장은 행력의 오른쪽 위쪽(row가 0이고 column이 1 ) 위치에 1.5 값을 설정하고, 왼족 아래(row가 1이고 column이 0 ) 위치에 3.2값을 설정하기 위해, 서브스크립트의 setter를 호출합니다.

Matrix 서브스크립트의 getter와 setter 모두 서브스크립트의 row와 column 값이 유효한지 assertion을 확인합니다. 이 assertion을 지원하기 위해, Matrix는 요청된 row와 column가 행력의 범위 안에 있는지 확인하기 위해, 편리한 메소드 indexIsValid(row:column:)을 가지고 있습니다.

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


'Swift > Language Guide' 카테고리의 다른 글

Initialization  (0) 2018.09.17
Inheritance  (0) 2018.08.30
Subscripts  (0) 2018.08.30
Methods  (0) 2018.08.30
Properties  (0) 2018.08.30
Structures and Classes  (0) 2018.08.30
Posted by 까칠코더