클래스, 구조체와 열거형은 컬렉션, 리스트 또는 순서들의 집합의 멤버 요소에 접근하기 위해 단축키인 서브스크립트를 정의할 수 있다. 설정과 검색을 위한 별도의 메소드 필요 없이 인덱스를 통해 값의 검색과 설정을 위해 서브스크립트를 사용한다. 예를 들어, someArray[index]
로 배열의 요소에 접근이 가능하고 딕셔너리의 예는, someDictionary[key]
로 가능하다.
하나의 타입의 여러 서브스크립트를 정의가능하고, 서브스크립트에 전달한 인덱스 값의 타입에 기초하여 적절한 서브스크립트를 선택할 수 있다. 서브스크립트는 하나의 차원에 제한되지 않고, 사용자가 설정한 타입의 필요에 맞게 여러 파라미터를 정의 가능하다.
서브스크립트는 인스턴스 이름 뒤에 대괄호 안에 하나 이상의 값을 작성함으로써 타입의 인스턴스를 검색하게 해준다. 이 구문은 인스턴스 메소드 구문과 계산된 프로퍼티 구문과 유사하다. subscript
키워드로 서브스크립트를 정의 가능하고, 인스턴스 메소드의 방식과 같이, 하나 이상의 입력 파라미터와 리턴타입을 지정한다. 인스턴스 메소드와 다르게, 서브스크립트는 읽기-쓰기 또는 읽기 전용이다. 이 동작은 게터와 세터에 의해 전달되고, 이는 계산된 프로퍼티와 동일한 방식이다.
subscript(index: Int) -> Int {
get {
// Return an appropriate subscript value here.
}
set(newValue) {
// Perform a suitable setting action here.
}
}
newValue
의 타입은 서브스크립트의 리턴값과 같다. 계산된 프로퍼티와 마찬가지로, 세터의 파라미터를 지정하지 않아도 고를 수 있다. 기본 파라미터는 newValue
로 불리며 직접 제공하지 않았다면 세터에 제공된다.
읽기 전용 계산된 속성과 마찬가지로, get
키워드를 제거함으로서 읽기-전용 프로퍼티를 간단히 선언 가능하다.
subscript(index: Int) -> Int {
// Return an appropriate subscript value here.
}
// 읽기-전용 서브스크립트 구현
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"
위 예에서, 서브스크립트를 호출함(threeTimesTable[6]
)으로써 threeTimesTable
인스턴스를 검색 가능하다. 이것은 three-times-table
의 6번째 항목을 요청한다.
NOTE
위 몇배수 테이블은 고정된 수학적 룰을 따른다. 새로운 값을 설정하기에는 적절하지 않고, 그래서 위 서브스크립트는 읽기전용 프로퍼티로서 정의된다.
서브스크립트의 정확한 의미는 사용되는 문맥의 위치에 따라 다르다. 서브스크립트는 컬렉션, 리스트, 순서형의 멤버요소에 접근을 하기위한 단축키로 보통 사용된다. 특정 클래스 또는 구조체의 기능에 가장 적절한 방식으로 서브스크립트를 자유롭게 구현할 수 있다.
예를 들어, 스위프트의 딕셔너리 타입은 딕셔너리 인스턴스안의 저장된 값의 검색과 설정을 위해 서브스크립트를 구현한다. 서브스크립트 대괄호에 딕셔너리의 키타입의 키를 제공하고, 서브스크립트에 딕셔너리의 값타입의 값을 할당하여 값을 설정할 수 있다.
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2
위의 딕셔너리의 타입은 [String: Int]
로 유추된다.
NOTE
스위프트의 딕셔너리 타입은 옵셔널타입을 리턴하고 가지는 서브스크립트인 키-값 서브스크립트를 구현한다. 위의 예시에 딕셔너리의 경우, 키-값 서브스크립트는Int? or optional int
타입의 값을 가지거나 반환한다. 딕셔너리 타입은 모든 키가 값을 가지지 않는 사실을 모델링 하고, 해당 키에nil
을 할당함으로써 삭제할 방법을 제공하기 위해 옵셔널 서브스크립트 타입을 사용한다.
서브스크립트는 입력 파라미터로 여러수를 받을수 있고, 이 입력파라미터는 어떤 타입이여도 상관없다. 또한 서브스크립트는 어떠한 타입의 값도 리턴한다.
함수와 같이 서브스크립트는 다양한 수의 파라미터를 가질수 있고 해당 파라미터의 기본값을 제공한다. 함수와 다르게 서브스크립트는 인-아웃 파라미터는 사용이 불가하다.
클래스 또는 구조체는 필요하다면 여러 서브스크립트의 구현을 제공할 수 있고, 사용할 적절한 서브스크립트는 값의 타입 또는 서브스크립트 대괄호에 포함된 값에 기반하여 유추되어진다. 이 여러한 서브스크립트의 정의는 서브스크립트 오버로딩(subscript overloading
)으로 알려져있다.
하나의 파라미터를 가지는 서브스크립트가 가장 일반적이지만, 타입에 맞게 여러 파라미터를 포함하는 서브스크립트 또한 정의가 가능하다. 아래의 두개의 정수 파라미터를 가지는 구조체 예시.
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
}
}
}
위 매트릭스는 이니셜라이저를 제공하고 더블 타입의 rows * columns
값을 저장하기 충분히 큰 배열을 만든다. 배열의 각 위치는 초기값으로 0.0이 주어진다. 이를 얻기 위해, 배열의 사이즈, 초기 값이 해당 사이즈의 새 배열을 초기화 하고 만드는 이니셜라이저에 전달된다.
// 적당한 열과 행 값을 주어 매트릭스 인스턴스를 만들 수 있다.
var matrix = Matrix(rows: 2, columns: 2)
이 매트릭스 인스턴스에 대한 그리드 배열은 2차원 배열을 왼쪽 위에서 오른쪽 아래로 읽을때 효과적인 평평한(1차원) 배열이다.
원래의 2차원 배열 그림
// 값을 설정하는 모습
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
매트릭스 구문의 게터와 세터는 둘다 서브스크립트의 열과 행의 값이 유효한지 확인하기 위한 어설션(assertion)이 포함되어 있다. 이 주장을 돕기 위해 매트릭스는 indexIsValid(row:column:)
로 불리는 편리한 메소드를 포함하고, 이는 열과 행이 매트릭스의 경계 내부에 있는지 체크한다.
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
let someValue = matrix[2, 2]
// 어설션이 발생한다. 범위 밖이기 때문.
위에 설명처럼 인스턴스 서브스크립트는 특정 타입의 인스턴스에서 호출하는 서브스크립트이다. 타입내에서 스스로 호출하는 서브스크립트를 정의가 가능하다. 이러한 서브스크립트를 타입 서브스크립트라고 부른다. 서브스크립트 키워드 앞에 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)
// mars 출력