🤔 Subscript란?
[ ] 을 이용하여 (단축키 처럼)값에 접근할 수 있도록 해주는 문법이다.
우리가 Array에서 [index] 를 사용해서 접근하거나, Dictionary 에 [key] 값으로 접근 했던 문법들은 subscript 로 구현되어 있는 것이었다.
클래스, 구조체, 그리고 열거형은 콜렉션, 목록, 또는 시퀀스의 멤버 요소에 서브스크립트를 구현해 줄 수 있다.
📖 Subscript 문법
subscript(index: Int) -> Int {
get {
// Return an appropriate subscript value here.
}
set(newValue) {
// Perform a suitable setting action here.
}
}
연산 프로퍼티의 문법과 아주 유사하다.
파라미터에는 [] 에 어떤 값이 들어올 것인지를 넣어주면 된다.
get 에 값을 접근할 때의 구현을
set 에 값을 변경할 때의 구현을
해주면 된다.
(연산프로퍼티 처럼 get-only가 가능하다)
⚙️ Subscript 구현 해보기
책과 저자의 이름이 순차적으로 저장 되어 있는 배열을 가지고 있는 BookLog 구조체를 만들어 보았다.
[책제목] 을 입력하면 저자 이름을 받아볼 수 있는 문법을 작성했다.
struct BookLog {
var list = ["어린왕자", "생텍쥐페리", "이상한 나라의 앨리스", "루이스 캐럴", "크리스마스 캐럴", "찰스 디킨스"]
subscript(bookTitle: String) -> String? {
guard let bookIndex = list.firstIndex(of: bookTitle) else {
return nil }
// 접근할 수 없는 값이면 nil 을 리턴
let intIndex = Int(bookIndex)
//bookIndex 타입이 Array<String>.Index 이기 때문에 변환
return list[intIndex + 1]
}
}
let myBookLog = BookLog()
print(myBookLog["어린왕자"])
//optional("생텍쥐페리")
👍🏻 Subscript 특징들
여러개의 서브 스크립트
하나의 객채가 여러개 서브 스크립트를 가지는 것이 가능하다.
인덱스의 값에 따라 어떤 서브스크립트를 사용하는 것인지를 알 수 있다.
(마치 init 같다.)
Subscript Options
Subscript 는 여러개의 파라미터를 가질 수도 있다.
함수처럼 ... 을 사용해서 가변 파라미터를 가질 수도 있고
= 을 사용해서 파라미터 기본 값을 가질 수도 있다.
Type Subscripts
static 키워드를 사용해서 타입 프로퍼티, 타입 메서드를 만들듯이 타입 서브스크립트를 만드는 것도 가능하다.
😳 String 에도 Subscript 가 구현되어 있다
String 타입도 Chracter 단위로 Subscript 문법에 접근할 수 가 있을까?
let text: String = "Hello swift🦜"
text[0]
이런 식의 코드를 작성하면
🚫'subscript(_:)' is unavailable: cannot subscript String with an Int, use a String.Index instead.
String 의 서브스크립트는 Int 로 접근할 수 없어 String.Index 타입을 사용해
라는 오류 메세지를 볼 수 있다.
public subscript(r: Range<String.Index>) -> Substring { get }
String Subscript 의 구현부를 찾아 보았다.
String에도 Subscript가 존재한다. 그런데 파라미터 타입이 String.Index 이다. 그리고 Substring 타입을 리턴하고 있다.
아까 위의 코드에서 보면 우리는 firstIndex 메서드가 String.Index? 타입을 리턴한다는 것을 알고 있다. (대부분의 String의 인덱스를 다루는 메서드의 리턴 타입이 String.Index 타입이다.)
let text: String = "Hello swift🦜"
let index = text.firstIndex(of: "s")!
text[index]
//s
이렇게 서브스트링 안에 String.Index 타입을 넣어주니 잘 작동한다.
만약 어레이 처럼 Int 값을 넣어서도 Chracter 를 리턴하게 해주고 싶으면 어떻게 해야 할까?
extension String {
subscript(idx: Int) -> String? {
guard (0..<count).contains(idx) else {
return nil
}
let target = index(startIndex, offsetBy: idx)
return String(self[target])
}
}
이런 방식으로 구현하면 된다. 이미 있던 서브스크립트를 활용해서!
이 코드는 소들이 님이 구현하신 코드이다.
소들이님 블로그에서 코드 보기
➕ String 의 인덱스 관련 프로퍼티와 메서드
var startIndex: String.Index { get }
문자열의 시작 요소 인덱스값
var endIndex: String.Index { get }
문자열의 마지막 요소 인덱스값
func index(after i: String.Index) -> String.Index
주어진 인덱스 값의 바로 다음 인덱스를 리턴하는 메서드
func index(before i: String.Index) -> String.Index
주어진 인덱스 값의 바로 전 인덱스를 리턴하는 메서드
func index(_ i: String.Index, offsetBy n: String.IndexDistance) -> String.Index
주어진 인덱스(i) 에서 offsetBy 만큼 떨어진 인덱스의 값을 리턴하는 메서드
func index(_ i: String.Index, offsetBy n: String.IndexDistance, limitedBy limit: String.Index) -> String.Index?
주어진 인덱스(i) 에서 offsetBy 만큼 떨어진 인덱스의 값을 리턴
firstIndex(of: Character), lastIndex(of: Character) : 인자로 들어온 문자가 몇번째 인덱스에 있는지 (Optional)
참고자료
'🍎 iOS > 🕊️ swift' 카테고리의 다른 글
[swift] 부동 소수점 오류가 나는 이유 (0) | 2023.01.06 |
---|---|
[swift] 고차 함수 요목조목 보기 (0) | 2023.01.06 |
[iOS] Number Fomatter (0) | 2023.01.06 |
[swift] String.Index 는 무엇일까? (0) | 2023.01.06 |
[swift] Substring는 왜 있는 걸까? (0) | 2023.01.06 |