References
Contents
- Subscript Syntax
- Subscript Usage
- Subscript Options
- Type Subscripts
클래스, 구조체, 열거형은 subscripts(서브스크립트)를 정의할 수 있는데, 서브스크립트는 콜렉션(collection), 리스트, 시퀀스의 멤버 요소에 접근할 수 있는 shortcut 입니다. 서브스크립트를 사용하면 다른 메소드없이 인덱스를 사용하여 값을 설정하고 검색할 수 있습니다. 예를 들어, 배열 인스턴스의 요소는 someArray[index]로 액세스하고 딕셔너리의 요소는 someDictionary[key]로 액세스할 수 있습니다.
단일 타입에 대해 여러 서브스크립트를 정의할 수 있고, 서브스크립트에 전달되는 인덱스 값의 타입에 따라서 적절할 서브스크립트 오버로드가 사용됩니다. 서브스크립트는 단일 차원에 한정되지 않고 사용자 정의 타입에 따라 여러 입력 파라미터를 사용하는 서브스크립트를 정의할 수도 있습니다.
Subscript Syntax
서브스크립트를 사용하면 인스턴스 이름 뒤 대괄호에 하나 이상의 값을 사용하여 해당 타입의 인스턴스를 쿼리할 수 있습니다. 이 문법은 인스턴스 메소드 문법과 연산 속성(computed property) 문법과 유사합니다. 서브스크립트 정의는 subscript 키워드로 정의하고, 하나 이상의 파라미터와 리턴 타입을 지정합니다. 인스턴스 메소드와는 달리 서브스크립트는 read-write 또는 read-only일 수 있습니다. 이 동작은 연산 속성(computed property)과 같은 방식으로 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라는 기본 파라미터가 setter에 제공됩니다.
읽기 전용(read-only) 연산 속성과 마찬가지로 get 키워드와 get의 중괄호를 제거하여 읽기 전용 서브스크립트로 선언할 수 있습니다.
subscript(index: Int) -> Int {
// Return an appropriate subscript value here.
}
아래는 읽기 전용 서브스크립트가 구현되어 있는 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"
이 예제코드에서 TimesTable 인스턴스는 three-time-table을 표현합니다. 구조체의 이니셜라이저에 3이라는 값이 전달되었고 이 값은 인스턴스의 multiplier 파라미터의 값으로 사용됩니다.
위에서 보다시피 threeTimesTable[6]과 같은 서브스크립트를 호출하여 threeTimesTable 인스턴스를 쿼리할 수 있습니다. 서브스크립트에 전달된 값에 3배인 18을 리턴합니다.
Subscript Usage
"subscript"의 정확한 의미는 서브스크립트가 사용되는 문맥에 달려있습니다. 일반적으로 서브스크립트는 콜렉션이나 리스트, 시퀀스에서 멤버 요소에 액세스하기 위한 shortcut으로 사용됩니다. 하지만 특정 클래스가 구조체의 기능을 위해 가장 적절한 방법으로 서브스크립트를 자유롭게 구현할 수 있습니다.
예를 들어, 스위프트의 딕셔너리 타입은 서브스크립트를 딕셔너리 인스턴스에서 저장되어 있는 값을 설정하거나 탐색하도록 구현합니다. 딕셔너리에서 서브스크립트 대괄호 안에 딕셔너리 키 타입의 키를 전달하고 딕셔너리 value 타입의 값을 할당하여 값을 설정할 수 있습니다.
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2
위 예제는 numberOfLegs라는 변수를 정의하고 3게의 key-value 쌍을 포함하는 딕셔너리 리터럴로 초기화합니다. numberOfLegs 딕셔너리의 타입은 [String: Int]에 의해 추론됩니다. 딕셔너리가 생성된 후에 이 예제는 서브스크립트 할당을 사용하여 "bird"라는 String 키를 추가하고 2라는 Int 값을 할당합니다.
Subscript Options
서브스크립트는 여러 개의 input 파라미터를 취할 수 있고, 이 파라미터는 어떠한 타입이든지 상관없습니다. 스크립트는 어떤 타입의 값 또한 반환할 수 있습니다.
함수처럼, 서브스크립트는 다양한 개수의 파라미터를 취할 수 있고, 파라미터의 기본값을 설정할 수 있습니다. 그러나 함수와는 달리 서브스크립트에서 in-out 파라미터는 사용할 수 없습니다.
클래스와 구조체는 필요한 만큼의 서브스크립트를 구현할 수 있습니다. 그리고 구현된 서브스크립트들은 서브스크립트가 사용되는 순간에 대괄호 내의 값이나 값의 타입을 기반하여 적절한 서브스크립트가 선택되어 수행됩니다. 이렇게 여러 개의 서브스크립트를 정의하는 것을 subscript overloading이라고 합니다.
대부분의 경우, 서브스크립트는 하나의 파라미터만을 취하지만, 사용자 타입에 맞추어 여러 개의 파라미터를 받는 서브스크립트를 정의할 수도 있습니다. 아래 Matrix 구조체를 정의하는 예제 코드는 Double 값의 2차원 행렬을 표현합니다. Matrix 구조체의 서브스크립트는 두 개의 정수 파라미터를 전달받습니다.
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는 rows와 columns 라는 두 개의 파라미터를 전달받는 이니셜라이저를 제공하고, Double 타입의 rows*columns 개의 값을 저장할만큼 큰 배열을 생성합니다. 행렬의 각 요소들의 값은 0.0으로 초기화됩니다.
적절한 row와 column 값을 전달하여, 아래처럼 새로운 Matrix 인스턴스를 생성할 수 있습니다.
var matrix = Matrix(rows: 2, columns: 2)
방금 생성한 Matrix 인스턴스는 2개의 행과 열로 구성됩니다. Matrix 인스턴스의 grid 배열은 행렬을 1차원으로 표현하고 있고, 다음과 같이 읽을 수 있습니다.
행렬의 값은 서브스크립트에 row와 column 값을 전달하여 설정할 수 있습니다. row와 column 값은 콤마로 분리됩니다.
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
Matrix 서브스크립트의 getter와 setter는 둘 다 서브스크립트의 row와 column의 값이 유효한지 체크하는 assertion을 포함하고 있습니다. 이 assertion을 지원하기 위해서 Matrix는 indexIsValid(row:column:) 이라는 편리한 메소드를 포함하고 있고, 요청된 row와 column의 값이 행렬의 경계 내부에 있는지 확인합니다.
만약 행렬 외부에 접근하는 서브스크립트라면 assertion이 트리거됩니다.
let someValue = matrix[2, 2]
// This triggers an assert, because [2, 2] is outside of the matrix bounds.
Type Subscripts
위에서 설명한 것처럼 인스턴스 서브스크립트는 특정 타입의 인스턴스에서 호출할 수 있는 서브스크립트입니다. 타입 자체에서 호출할 수 있는 서브스크립트 또한 정의할 수 있는데, 이러한 타입의 서브스크립트를 type subscript라고 합니다. type subscript는 subscript 키워드 앞에 static 키워드를 추가하여 정의할 수 있습니다. 클래스에서는 class 키워드를 대신 사용합니다.
아래 예제 코드는 타입 서브스크립트를 정의하고 호출하는 방법을 보여줍니다.
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
static subscript(n: Int) -> Planet {
return Planet(rawValue: n)!
}
}
let mars = Planet[4]
print(mars)
'프로그래밍 > Swift' 카테고리의 다른 글
[Swift] Initialization (0) | 2022.01.03 |
---|---|
[Swift] Inheritance (상속) (0) | 2021.12.30 |
[Swift] Methods (0) | 2021.12.26 |
[Swift] Properties (0) | 2021.12.25 |
[Swift] Structures and Classes (구조체와 클래스) (0) | 2021.12.24 |
댓글