Notice
Recent Posts
Recent Comments
Link
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

일왓록(日What錄)

[Swift]Subscripts 공식문서 읽어보기 + String Subscript 구현 본문

iOS/Swift

[Swift]Subscripts 공식문서 읽어보기 + String Subscript 구현

일왓 2024. 4. 22. 02:23

Swift를 가지고 코딩테스트를 준비하면 치명적인 Swift의 단점을 발견할 수 있다.

바로 다른 언어들에서 지원하는 String의 Index를 통한 접근이 기본적으로 지원하지 않는 다는 것인데, 이를 해결하기 위해서는 Subscripts를 통해 직접 구현해야한다.

 

SubScripts에 대해 알아보자


Subscripts

콜렉션의 요소에 접근하는 방식

 

클래스, 구조체, 열거형은 콜렉션, 리스트, 또는 시퀀스의 멤버 요소에 접근할 수 있는 단축키(ShortCuts)인 서브 스크립트(subscripts)를 정의할 수 있다.

 

설정과 검색을 별도의 메서드 없이 인덱스로 값으로 구현하기 위해 서브 스크립트를 사용한다.

 

 

단순 텍스트로만 보면 이해하기가 쉽지 않을 수 있으나 코드로 보면 이해하기가 쉽다.

var someArray = ["hello", "world"]

someArray[0] //"hello"
someArray[1] //"world"

var someArray2 = ["first": "hello", "second": "world"]
someArray2["first"] //Optional("hello")
someArray2["second"] //Optional("world")

 

이렇게 index 혹은 key 값을 가지고 접근 및 설정을 할 수 있는 것을 알 것이다.

이런 방식을 지원하는게 subscripts인 것이다.

 

 

실제 Array의 구현을 보면 이렇게 구현되어 있는 것을 확인할 수 있다.


서브 스크립트 구문(Subscript Syntax)

서브 스크립트를 사용하면 인스턴스 이름 뒤에 대괄호에 하나 이상의 값을 작성하여 타입의 인스턴스를 조회할 수 있다.

이 구문은 인스턴스 연산 프로퍼티와 비슷하게 구현된다.

 

하나 이상의 입력 파라미터와 반환 타입을 작성한다.

read-only의 형태와 read-write 형태 모두 구현이 가능하다.

subscript(index: Int) -> Int {
    get {
        // Return an appropriate subscript value here.
    }
    set(newValue) {
        // Perform a suitable setting action here.
    }
}

newValue의 타입은 서브스크립트의 반환 값과 동일하다.

 

read-only 형태로 구현하고자 한다면 다음과 같이 선언하면 된다.

subscript(index: Int) -> Int {
    // Return an appropriate subscript value here.
}

 

이를 활용해서 다음과 같은 예제를 실행시킬 수 있다.

struct TimesTable {
    let multiplier: Int
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])") //subscript(index: 6)를 호출
// Prints "six times three is 18"

서브 스크립트 사용(Subscript Usage)

var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2

위에서도 코드를 보였듯이 다음과 같이 사용할 수 있다.

 

사용되는 상황에 따라 다르지만, 콜렉션, 리스트, 시퀀스 멤버 요소에 바로 접근하는 방식으로 사용된다.

자유롭게 정의하여 원하는 방식으로 구현이 가능한 것이다.


서브 스크립트 옵션(Subscript Options)

서브 스크립트는 여러개의 입력 파라미터를 가질 수 있고 어떤 타입의 파라미터라도 가능하다.

또한 파라미터의 타입 또는 대괄호 내에서 포함된 값을 기반으로 오버로딩을 사용하여 적절한 서브 스크립트를 구현할 수 있다.

(subscript overloading)

하지만 in-out 파라미터는 사용이 불가하다.

 

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)
    }
    func indexIsValid(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    subscript(row: Int, column: Int) -> Double {
        get {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}

 

선언시 rows와 columns를 받고 그 행열 값에 맞게 0.0으로 초기화 하는 Matrix 구조체를 선언한다.

 

그러고 subscript를 통해 접근하려는 행열의 값이 맞는 접근인지 확인하고 맞는 행열 값을 검색 또는 접근하려고 한다면 작업을 수행하는 코드이다.

 

var matrix = Matrix(rows: 2, columns: 2)

 

선언한다면 matrix는 다음과 같이 선언된다.

https://docs.swift.org/swift-book/images/subscriptMatrix01@2x.png

 

matrix[0, 1] = 1.5
matrix[1, 0] = 3.2

 

https://docs.swift.org/swift-book/images/subscriptMatrix01@2x.png

 

 


타입 서브 스크립트(Type Subscripts)

타입 자체에서 호출되는 서브스크립트도 정의할 수 있다.

이를 타입 서브스크립트라 부른다.

 

subscript 키워드 앞에 static / class를 붙여 구현하면 된다.

상속을 받아 재정의(오버라이딩)가 필요한 경우라면 class를 붙여 구현하면 되고 그게 아니라면 static 키워드를 사용하면 된다.

 

enum Week: Int {
    case mon = 1, tues, wed, thu, fri, sat, sun
    static subscript(n: Int) -> Week {
        return Week(rawValue: n)!
    }
}
let thu = Week[4]
print(thu) //thu

 


공식문서 이외 추가 작성

문자열 서브 스크립트 (String Subscript)

 

사실 이부분을 위해 공식문서를 파헤쳐 본 것이다.

위에서 언급한 바와 같이 다른 언어들에서는 문자열에 대한 배열 접근이 가능하지만 Swift는 기본적으로 문자열 배열 접근을 지원하지 않아 서브 스크립트를 통하여 구현해주어야 한다.

구현 코드는 다음과 같다.

extension String {
    subscript(idx: Int) -> String? {
        guard (0..<count).contains(idx) else { return nil } // 인덱스 범주 체크 : 인덱스 범위 초과시 nil 리턴
        let result = index(startIndex, offsetBy: idx) //idx로 넘겨진 index 값에 대한 String.Index 리턴
        return String(self[result]) //String.Index를 통해 접근
    }

 

정확히 말하자면 단순히 Int를 통해 배열 접근이 불가해서 Int를 통해 index에 접근하고자 한다면 다음과 같이 구현해주어야 한다.

 

 

 

 

 


⚠️참고문헌

 

서브 스크립트 (Subscripts) | Swift

콜렉션의 요소에 접근합니다. 클래스, 구조체, 그리고 열거형은 콜렉션, 리스트, 또는 시퀀스의 멤버 요소에 접근할 수 있는 단축키인 서브 스크립트 (subscripts) 를 정의할 수 있습니다. 설정과 검

bbiguduk.gitbook.io

 

 

Documentation

 

docs.swift.org

 

 

Swift) 서브스크립트(Subscript) 정복하기

안녕하세요!?! 소들입니다!!!!!!!!! :D 오늘은 서브스크립트(Subscript)에 대해 알아볼 거예요!!! 이렇게 하나하나 Swift를 정복하다보면.. 언젠가 Swift 왕이 되어 있기를 간절히 바라며.....👑 이번에도

babbab2.tistory.com

 

 

⚠️이 글은 필자가 공식문서를 중심으로 블로그 등을 통해 습득한 내용을 정리해보면서 다시 공부하는 글입니다. 개념을 습득하는 과정 중 잘못된 개념이 있을 수 있으니 그 점에 유의하시길 바라며, 잘못된 내용은 피드백을 해주시면 감사드리겠습니다.⚠️