안녕하세요.
이번에는 Swift의 subscript에 대해 알아볼게요.
클래서, 구조체, 열거형에서 subscript 정의가 가능합니다.
그럼 subscript란 무엇이냐?
subscript를 사용하면 collection, list, sequence의 element에 쉽게 접근할 수 있어요.
(Array의 someArray[index] 또는 Dictionary의 someDictionary[key] 처럼 말이죠!)
또한 하나의 타입에 여러 개의 subscript를 구현할 수 있고, overload도 가능해요.
## 1. Subscript Syntax
subscript 키워드를 사용해서 subscript를 정의할 수 있어요.
subscript는 read-write 또는 read-only로만 구현이 가능합니다.
아래처럼 getter, setter를 구현하면 read-write 인 것이고,
subscript(index: Int) -> Int {
get {
// Return an appropriate subscript value here.
}
set(newValue) {
// Perform a suitable setting action here.
}
}
아래처럼 setter를 생략하면 read-only인 것이에요ㅎㅎ
subscript(index: Int) -> Int {
get {
// Return an appropriate subscript value here.
}
}
또는
subscript(index: Int) -> Int {
// Return an appropriate subscript value here.
}
subscript를 구현했으면 사용방법도 알아야겠죠?
Array나 Dictionary처럼 인스턴스 이름 뒤에 value를 대괄호([])로 감싸주면 element에 접근이 가능해요.
즉, 아래처럼 사용할 수 있는 것이죠.
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])") // "six times three is 18"
threeTimesTable[6] = 10 ❎ // Cannot assign through subscript: subscript is get-only
마지막 줄을 보면 subscript가 read-only로 구현되어 있기 때문에, 값을 대입하려고 하니까 에러가 났습니다.
## 2. 여러 개의 SubScript
subscript는 여러 개를 구현할 수 있어요.
또한, subscript에 필요한 input parameter의 수도 제한이 없습니다.
예를 들어볼게요.
아래처럼 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)
}
}
1차원 배열인 grid의 element에 쉽게 접근하도록 subscript를 추가해볼까요?
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)
}
subscript(index: Int) -> Double { ✅
get {
return grid[index]
}
set {
grid[index] = newValue
}
}
}
matrix[3] = 2.0 // Matrix(rows: 2, columns: 2, grid: [0.0, 1.5, 0.0, 2.0])
그런데, 1차원인 grid를 아래같이 2차원 배열처럼 쓰고 싶을 수가 있겠죠?
이럴 때, row와 column을 input parameter로 받는 subscript를 추가로 구현해주면 쉽게 해결이 가능합니다.
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)
}
subscript(index: Int) -> Double {
get {
return grid[index]
}
set {
grid[index] = newValue
}
}
subscript(row: Int, column: Int) -> Double { ✅
get {
return grid[(row * columns) + column]
}
set {
grid[(row * columns) + column] = newValue
}
}
}
matrix[0, 1] = 1.5 // Matrix(rows: 2, columns: 2, grid: [0.0, 1.5, 0.0, 0.0])
## 3. Type Subscript
위에서 설명한 subscript는 정확하게 말하면 Instance Subscript라고 해요.
(특정 타입의 인스턴스에서 호출할 수 있는 subscript라는 의미죠.)
그런데, 특정 타입 그 자체에서 subscript도 호출할 수 있어요. 그것을 Type Subscript라고 부릅니다.
Type Subscript를 구현하려면, subscript 키워드 앞에 static 키워드를 붙여주면 됩니다.
(클래스에서 구현한다면 class 키워드를 대신 사용해도 괜찮아요.)
Type Subscript 예를 들어볼게요.
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
static + subscript 키워드를 사용해서 Type Subscript를 구현했기 때문에, Planet이란 enum 타입에 대괄호를 사용해서 element에 접근할 수 있게 됩니다ㅎㅎ
## 참고
- https://docs.swift.org/swift-book/LanguageGuide/Subscripts.html
이번 글은 여기서 마무리.
'Swift' 카테고리의 다른 글
클로저에서 [weak self] 사용할 때 주의할 점 (0) | 2022.04.16 |
---|---|
Automatic Reference Counting (ARC) (0) | 2022.04.10 |
Struct와 Class (0) | 2022.04.02 |
FormatStyle (0) | 2022.03.24 |
PersonNameComponents를 사용해서 이름 파싱하기 (0) | 2022.03.23 |