Classes, structures, and enumerations can define subscripts, which are shortcuts for accessing the member elements of a collection, list, or sequence. You use subscripts to set and retrieve values by index without needing separate methods for setting and retrieval. For example, you access elements in an
Array
instance assomeArray[index]
and elements in aDictionary
instance assomeDictionary[key]
.
- 클래스, 구조체, 및 열거형은, 집합체 (collection), 리스트 (list), 또는 시퀀스 (sequence) 멤버 원소에 접근하는 줄임말인, 첨자 (subscripts) 를 정의할 수 있습니다. 별도의 설정 및 검색 방법 없이 첨자를 사용하여 색인 (index) 별로 값을 설정하고 검색할 수 있습니다. 예를 들어,
Array
인스턴스 원소는someArray[index]
로Dictionary
인스턴스 원소는someDictionary[key]
로 접근합니다.
subscript
키워드로 작성하며, 인스턴스 메서드와 똑같이 하나 이상의 입력 매개변수와 반환 타입을 지정한다. 인스턴스 메서드와 달리, 첨자는 읽기-쓰기나 읽기 전용일 수 있다. 이런 동작은 연산 프로퍼티에서와 똑같이 getter
와 setter
로 전달된다.subscript(index: Int) -> Int {
get {
// 여기에 적절한 첨자 값을 반환합니다.
}
set(newValue) {
// 여기서 적절한 설정 작업을 수행합니다.
}
}
newValue
타입은 첨자의 반환 값과 똑같다. 연산 프로퍼티처럼, setter
의 (newValue)
매개변수를 지정하지 않을 수 있다. 만약 매개변수를 지정하지 않으면 newValue
라는 기본 매개 변수를 setter
에 제공한다.
get-only 연산 프로퍼티처럼, get
키워드와 괄호를 제거하여 get-only 첨자 정의를 단순하게 할 수 있다.
subscript(index: Int) -> Int {
// 여기에 적절한 첨자 값을 반환합니다.
}
TimesTable
구조체를 정의한 get-only 첨자 구현이다.struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print("3 곱하기 6은 \(threeTimesTable[6])")
// "3 곱하기 6은 18" 을 인쇄함
이 예제에선 3단을 나타내는 TimesTable
인스턴스를 생성한다. 이는 인스턴스의 multiplier
프로퍼티가 사용할 3
이라는 값을 구조체의 이니셜라이저에 전달함으로써 지시한다.
threeTimesTable[6]
이라는 호출로 보는 것처럼, 자신의 첨자를 호출함으로써 threeTimesTable
인스턴스를 조회할 수 있다. 이는 3단의 6번째 요소를 요청하여 18
, 혹은 3
곱하기 6
의 값을 반환한다.
구구단 n-단은 고정된 수학 규칙에 기초합니다. threeTimesTable[someIndex] 에 새 값을 설정하는 건 적절치 않으므로, TimesTable 의 첨자는 읽기-전용 첨자로 정의합니다.
첨자 (subscript) 의 정확한 의미는 자신을 사용한 곳의 상황에 따라 다르다. 첨자는 일반적으로 컬렉션, 리스트, 또는 시퀀스의 구성원 요소에 접근하기 위한 줄임말로 사용한다. 특정 클래스나 구조체 기능에 가장 적절한 방식으로 자유롭게 첨자를 구현할 수 있다.
예를 들어, 스위프트의 Dictionary
타입은 Dictionary
인스턴스에 저장한 값을 설정하고 가져오고자 첨자를 구현한다. 첨자 대괄호 안에 딕셔너리의 키 타입인 Key
를 제공하고, 첨자에 딕셔너리의 값 타입인 Value
를 할당함으로써, 딕셔너리에 값을 설정할 수 있다.
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2
numberOfLegs
라는 변수를 정의하고 3개의 키-값 쌍을 담은 딕셔너리로 이를 초기화한다. numberOfLegs
딕셔너리의 타입은 [String: Int]
라고 추론한다. 딕셔너리를 생성한 후, 이 예제는 첨자 할당을 사용하여 딕셔너리에 "bird"
라는 String
키와 2
라는 Int
값을 추가한다.스위프트의
Dictionary
타입은 옵셔널 (optional) 타입을 취하고 반환하는 첨자로 자신의 키-값 첨자 연산을 구현합니다. 위의numberOfLegs
딕셔너리에선, 키-값 첨자가Int?
, 또는 “옵셔널 정수 (optional int)”, 타입의 값을 취하고 반환합니다.Dictionary
타입은 옵셔널 첨자 타입을 사용하여 모든 키가 값을 가지진 않을 거라는 사실을 모델링하고, 그 키에nil
값을 할당함으로써 키의 값을 삭제할 방법을 제공합니다.
첨자는 임의의 개수의 입력 매개변수를 사용할 수 있으며, 이러한 입력 매개변수는 임의의 타입일 수 있다. 첨자는 모든 타입의 값을 반환할 수도 있다.
마치 함수처럼 첨자는 다양한 수의 매개변수를 사용할 수 있으며, 매개 변수에 대한 기본값을 제공할 수 있다. 그러나 in-out 파라미터는 사용할 수 없다.
클래스 혹은 구조체는 필요한 만큼의 첨자 구현을 제공할 수 있으며, 사용할 적절한 첨자는 첨자가 사용되는 시점에 첨자 대괄호 안에 포함된 값의 타입을 기반으로 추론된다. 이런 여러 개의 첨자 정의를 첨자 중복 정의 (subscript overloading) 라고 한다.
첨자가 단일 매개 변수를 사용하는 것이 가장 일반적이지만, 자신의 타입에 적절하다면 여러 개의 매개변수를 가진 첨자를 정의할 수도 있다. 다음 예제는, 2차원 Double
값 배열을 나타내는 Matrix
구조체를 정의한다. 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
이라는 두 매개변수를 취하는 이니셜라이저를 제공하며, rows * columns
개의 Double
타입 값을 저장할만큼 충분히 큰 배열을 생성한다. 행렬 (matrix)
안의 각 위치엔 0.0
이라는 초기 값을 준다.
자신의 이니셜라이저에 적절한 행과 열 개수를 전달함으로써 새로운 Matrix
인스턴스를 생성할 수 있다.
var matrix = Matrix(rows: 2, columns: 2)
Matrix
인스턴스를 생성합니다. 이 Matrix
인스턴스의 grid
배열은 사실상 맨 왼쪽 위에서 오른쪽 아래로 읽어가는, 납작한 버전의 행렬이다.'납작한 (flattened) 버전의 행렬' 이란 2차원 배열의 형상을 바꿔서 1차원 배열로 만들었다는 의미입니다.
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
setter
를 호출하여 (row
가 0 이고 column
이 1 인) 행렬 맨 오른쪽 위를 1.5 로, (row
가 1 이고 column
이 0 인) 맨 왼쪽 아래를 3.2 라는 값으로 설정한다.Matrix
첨자의 getter
와 setter
둘 다 첨자의 row
와 column
값이 유효한지 검사하는 단언문 (assertion) 을 담고 있다. 이 단언문을 지원하기 위해, 요청한 row
와 column
이 행렬 경계 안에 있는지 검사하는 indexIsValid(row:column:)
라는 편의를 위한 메소드를 가지고 있다.func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
let someValue = matrix[2, 2]
// [2, 2] 가 행렬 경계 밖이기 때문에, 단언문을 발동합니다.
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)