안녕하세요!?! 소들입니다!!!!!!!!! :D
오늘은 서브스크립트(Subscript)에 대해 알아볼 거예요!!!
이렇게 하나하나 Swift를 정복하다보면.. 언젠가 Swift 왕이 되어 있기를 간절히 바라며.....👑
이번에도 쉬운 내용이니 후딱 끝내겠습니다 :)
모든 포스팅은 편의 말투로 합니다~!!
1. 서브스크립트(Subscript)란?
클래스, 구조체, 열거형에서 시퀀스의 멤버 요소에 접근하기 위한 바로가기 첨자로,
단일 타입에 여러 서브스크립트를 정의할 수 있다
정의만 보면 이게 도대체 뭔 🐶소리인지^^;;;
사실 이름이 조금 어려울 뿐이지, 우린 지금껏 아~주 자연스럽게 서브스크립트를 써왔음
정의에서 "시퀀스" 멤버 요소에 접근하기 위한 것이라 했짢음!?!
대표적으로 우리가 배열을 사용하면서 원소에 값에 접근할 때
let nums: [Int] = [1, 2, 3, 4]
nums[0] // 1
nums[1] // 2
|
이렇게 [] 대괄호 안에 index를 넣어줘서 멤버 요소에 접근하잖음?!?!
이것이 바로 서브스크립트임!!!! 실제로 저 배열의 []의 정의를 따라가보면,
이렇게 정의되어 있음!!!!!!
아하! 배열의 서브스크립트는 parameter로 Int형을 index로 받고,
해당 index에 해당하는 Element를 반환하는 형태구나! 라는 것을 알 수 있음 :)
한 가지 더 예를 보자면, 이번엔 딕셔너리로 봐보겠음!!!!!
우리가 딕셔너리에서 Value에 접근할 때
let dict: [String: Int] = ["one": 1, "two": 2]
dict["one"] // 1
dict["two"] // 2
|
이렇게 [] 대괄호 안에 Key값을 넣어줘서 Value에 접근하잖음?!?!
이것이 바로바로 서브스크립트임!!!! 저 딕셔너리 []의 정의를 따라가보면,
이렇게 정의되어 있음 :)
아하! 딕셔너리의 서브스크립트는 Prameter로 Key를 받고,
해당 Key에 해당하는 Value를 반환하는 형태구나! 라는 것을 알 수 있음!
자, 서브스크립트가 어떤 것인지 이제 감이 완벽히 왔을 거라 믿고,
그럼 서브스크립트를 직접 사용하는 방법에 대해 알아봅세~.~
+
(더 나아간다면, 위에 딕셔너리의 서브스크립트 선언에서 일반적인 메서드 형태라면,
key는 argument label이자 parameter name이니까, 서브스크립트를 호출할 당시
[key: ] 이렇게 호출해야하는 거 아닌가여? 란 의문이 들 수 있는데, 이는 뒤에서 다룰 거니 일단 스킵!!)
2. 서브스크립트 정의하기
subscript 키워드로 작성하며 하나 이상의 파라미터와 반환 값을 지정한다
파라미터나 리턴형을 생략할 수 없고, getter와 setter 모두 구현할 수 있다
get-only는 가능하지만, set-only는 불가하다 (getter 생략 불가)
subscript(index: Int) -> Int {
get {
}
set(newValue) {
}
}
|
서브스크립트 정의는 위와 같은 방식으로 하는데, 마치 연산 프로퍼티와 비슷하고
실제로 연산 프로퍼티와 get/set의 성질은 거의 비슷함!!!!
setter의 경우 파라미터를 생략하면 newValue로 접근할 수 있는 것 또한 같고,
get-only일 경우 get 구문 생략 가능한 것도 같음(이해 안가면 연산 프로퍼티부터 공부하시길..!)
음.. 위 선언만으론 잘 와닿지 않을 수 있으니 다른 예제로 보겠음!!!!
우리가 알고리즘을 풀 때나 가끔 String을 쓸 때 너무도 원하는 것...
String도 배열처럼 [index]로 접근하고 싶다!!!!!!!!! 느낄 ㄸㅐ 있지 않음!?!?!
let sodeul = "Hello, Sodeul!"
sodeul[0] // error!!
|
sodeul[0]을 쓰면, 배열 처럼 "H"가 반환되면 참 좋겄다만 실제론 에러임ㅎ
어떤 에러냐? 해당 서브스크립트를 사용할 수 없다는 에러임!! 근데 우린 이제 서브스크립트가 뭔지 알았잖음 :) ??
따라서 String을 확장해서 서브스크립트를 직접 다음과 같이 작성해주면,
extension String {
subscript(idx: Int) -> String? {
guard (0..<count).contains(idx) else {
return nil
}
let target = index(startIndex, offsetBy: idx)
return String(self[target])
}
}
|
위와 같이 extension을 통해 서브스크립트를 직접 구현해주면,
let sodeul = "Hello, Sodeul!"
sodeul[0] // Optional("H")
sodeul[100] // nil
|
이렇게 []를 통해 내가 원하는 index의 문자에 접근할 수 있음!!ㅎㅎ
이런 것이 바로 서브스크립트..!
2-1. 만약 Argument Label을 사용하고 싶다면..
위에서 잠깐 의문점?이 들 수 있다고 말했는데,
서브스크립트는 파라미터 선언 당시 Argument Label을 _로 처리해주지 않아도,
Argument Label로 사용되지 않음..! Only Parameter Name..!!
subscript(index: Int) -> Int {
get {
}
set(newValue) {
}
}
|
따라서, 선언은 저렇지만 실제 서브스크립트를 호출할 때도
index란 Argument Label 없이 호출하는 것임..! 근데 만약 굳이 굳이 써주고 싶다면,
subscript(index index: Int) -> Int {
get {
}
set(newValue) {
}
}
|
이렇게 써주면... 뭐 실제 서브스크립트를 사용할 때도,
subscript[index: 0]
|
이렇게 Argument Label을 넣어줄 순 있는데...
웬만해선 ................ 쓰지...... 않는........... 것이.......(안 쓰는 데엔 다 이유가....)
3. 서브스크립트 사용하기
뭐..... 위에서 다 봤찌만...
struct Stack {
var stack: [Int] = [0, 1, 2, 3, 4, 5]
subscript(index: Int) -> Int {
get {
return stack[index]
}
set {
stack[index] = newValue
}
}
}
|
만약 Stack이란 구조체에 서브스크립트를 위처럼 구현했을 경우,
var stack: Stack = .init()
stack[0] // 서브스크립트 getter 접근
stack[1] = 2 // 서브스크립트 setter 접근
|
이렇게 []를 통해 getter / setter에 접근할 수 있음 :)
4. 타입 서브스크립트(Type Subscript)
타입 프로퍼티 / 타입 메서드에서 공부 했듯이
서브스크립트 또한 타입 서브스크립트로 선언이 가능함!!!!
(인스턴스 vs 타입은 이전에 다뤘으니 깊게 안하고 넘어감!)
struct Stack {
static var stack: [Int] = [0, 1, 2, 3]
static subscript(index: Int) -> Int {
return stack[index]
}
}
|
이렇게!!
오버라이딩이 불가하다면 static / 가능하다면 class로 선언해주면
타입 서브스크립트가 되는 것임!!!
Stack[0] // 0
Stack[1] // 1
|
실제로, 인스턴스 없이 "타입 이름"에 대고 호출이 가능함!
.
.
.
서브스크립트 포스팅 끝:)
잘못된 점 & 궁금한 점은 언제든!! 댓글 주세요
피드백 대환영입니다~
'iOS > Swift' 카테고리의 다른 글
Swift) 상속(Inheritance) 정복하기 (1/2) - 상속이란? (8) | 2021.03.15 |
---|---|
Swift) 확장(extension) 정복하기 (5) | 2021.03.10 |
Swift) static? class? 메서드 완벽 정복하기 (4) | 2021.03.05 |
Swift) 프로퍼티 정복하기 (4/4) - 프로퍼티 옵저버(Property Observer) (2) | 2021.03.03 |
Swift) 프로퍼티 정복하기 (3/4) - 타입 프로퍼티(Type Property) (8) | 2021.03.02 |