질문 배경:
서브스크립트는 대괄호를 사용하여 컬렉션, 구조체 및 기타 유형 내의 값에 접근하는 메커니즘입니다. 이는 스위프트에 추가된 다른 언어들과 유사하게 배열의 인덱싱(Python), [] 연산자(C++/Java) 등의 방법으로 컬렉션 및 유사 객체 작업을 보다 직관적으로 만들기 위함입니다.
문제:
모든 유형은 기본적으로 배열처럼 인덱스에 대한 접근을 지원하지 않습니다. 데이터가 있는 구조체나 클래스가 있을 때, 요소에 접근하는 것이 익숙한 구문(예: myObject[index])을 통해 구현하는 것이 더 합리적입니다.
해결책:
스위프트는 사용자 정의 형식에 대해 스스로 서브스크립트를 구현할 수 있게 해줍니다. 이를 읽기 전용 또는 쓰기 전용으로 만들 수 있습니다. 예를 들어, 정사각 행렬을 다루기 위해 서브스크립트를 구현하는 구조체 예제:
struct Matrix { let size: Int private var grid: [Int] init(size: Int) { self.size = size self.grid = Array(repeating: 0, count: size * size) } subscript(row: Int, column: Int) -> Int { get { precondition(indexIsValid(row, column), "Index out of range") return grid[(row * size) + column] } set { precondition(indexIsValid(row, column), "Index out of range") grid[(row * size) + column] = newValue } } private func indexIsValid(_ row: Int, _ column: Int) -> Bool { return row >= 0 && row < size && column >= 0 && column < size } } var m = Matrix(size: 3) m[1,2] = 7 print(m[1,2]) // 7
주요 특징:
subscript 키워드를 사용하여 구현되며, 읽기 전용 또는 읽기/쓰기 모두 가능합니다.서브스크립트는 컬렉션에만 사용할 수 있나요?
아니요, 서브스크립트는 구조체, 클래스, 열거형 등 모든 유형에 대해 구현할 수 있습니다. 내부 데이터 유형이 반드시 컬렉션일 필요는 없으며, 중요한 것은 서브스크립트를 통해 요청을 처리하는 로직입니다.
하나의 유형에 대해 서로 다른 시그니처의 서브스크립트를 여러 개 만들 수 있나요?
네, 서로 다른 매개변수 시그니처로 서브스크립트를 오버로드하는 것이 허용됩니다:
struct Example { subscript(index: Int) -> Int { return index } subscript(key: String) -> String { return key.uppercased() } }
set 없이 computed property로서 서브스크립트를 사용할 수 있나요?
네, 서브스크립트는 읽기 전용(get-only)일 수 있으며, 이 경우 쓰기 시도가 컴파일 오류를 발생시킵니다.
struct ReadOnly { subscript(index: Int) -> Int { index * index } }
대형 구조체에 서브스크립트를 구현했으나 범위 검사를 하지 않아 잘못된 인덱스 시도가 있을 경우 애플리케이션이 충돌하는 경우.
장점:
단점:
행렬은 인덱스 범위에 대한 사전 조건을 구현했습니다. 어떤 오류도 즉시 포착되어 프로덕션에 들어가지 않습니다.
장점:
단점: