클래스, 구조체, 열거형에서 시퀀스의 멤버 요소에 접근하기 위한 바로가기 첨자
// 배열에서 시퀀스 값에 접근할 때 [] 대괄호 안에 index를 넣어줘서 멤버 요소에 접근하는데 이것이 subscript이다.
let nums: [Int] = [1, 2, 3, 4]
nums[0] // 1
nums[1] // 2
// swift에 정의되어있는 배열의 [] 정의
@inlinable public subscript(index: Int) -> Element
// Dictionary의 value 접근할 때도 subscript 사용
let dictionary: [String: Int] = ["one": 1, "two": 2]
dictionary["one"] // 1
dictionary["two"] // 2
// swift에 정의되어있는 Dictionary의 [] 정의
@inlinable public subscript(key: Key) -> Value?
💡 왜 서브스크립트를 호출할 당시 (index: )
, [key: ]
로 호출하지 않는지?
일반 메소드라면 외부 매개변수로 호출해야하지만 subscipt는 파라미터 선언 당시 외부 매개변수를 _
로 쓰지않아도 외부 매개변수로 사용되지 않는다.
단일 타입에 여러 서브스크립트를 정의할 수 있다. subscript 키워드로 작성하며 하나 이상의 파라미터와 반환 값을 지정한다. 파라미터나 리턴형을 생략할 수 없고, getter
와 setter
모두 구현할 수 있다. setter
는 생략가능하지만 getter
는 생략 불가능하다.
// 서브스크립트 정의는 마치 연산 프로퍼티와 비슷하다.
// setter의 경우 파라미터를 생략하면 newValue로 접근할 수 있고 get-only일 경우 `get`을 생략 가능한 것도 연산 프로퍼티와 같다.
subscript(index: Int) -> Int {
get {
}
set(newValue) {
}
}
// 원래 swift에서 string은 배열처럼 string[index]로 접근 불가능하다.
// subscript를 통해 직접 정의해주면 사용 가능하다.
extension String {
subscript(idx: Int) -> String? {
guard (0..<count).contains(idx) else {
return nil
}
let target = index(startIndex, offsetBy: idx)
return String(self[target])
}
}
let string = "Hello, Swift!"
print(string[0]) // 출력값: Optional("H")
print(string[100]) //출력값: nil
struct Stack {
var stack: [Int] = [0, 1, 2, 3, 4, 5]
subscript(index: Int) -> Int {
get {
return stack[index]
}
set {
stack[index] = newValue
}
}
}
var stack = Stack()
// getter 접근
print(stack[0])
// setter 접근
stack[1] = 9
print(stack[1]) // 출력값: 9
오버라이딩이 불가하다면 static / 가능하다면 class로 선언해주면 타입 subscript이 된다.
struct Stack2 {
static var stack: [Int] = [0, 1, 2, 3]
static subscript(index: Int) -> Int {
return stack[index]
}
}
// 인스턴스 없이 타입 이름으로 호출이 가능하다.
print(Stack2[0]) // 출력값: 0