Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

서브스크립트 #48

Open
simoniful opened this issue Oct 25, 2022 · 0 comments
Open

서브스크립트 #48

simoniful opened this issue Oct 25, 2022 · 0 comments

Comments

@simoniful
Copy link
Owner

simoniful commented Oct 25, 2022

클래스, 구조체, 열거형은 컬렉션, 리스트, 시퀀스의 멤버 원소에 쉽게 접근할 수 있는 서브스크립트(subscript)를 정의 할 수 있다
다른 메소드를 사용할 필요 없이, 인덱스를 통해 값을 설정하거나 찾을 수 있다
ex. 배열 인스턴스의 원소에 someArray[index]와 같이 접근
ex. 딕셔너리의 원소에는 someDictionary[key]와 같이 접근

단일 타입에 대해 여러 서브스크립트를 정의할 수 있고,
서브스크립트에 넣는 인덱스 값의 타입에 따라 적당한 서브스크립트를 오버로드하게 된다

서브스크립트는 일차원 공간에만 한정되지 않으며,
커스텀 타입의 필요에 맞춰 여러 매개 변수를 사용하여 서브스크립트를 정의 가능

서브스크립트 문법

서브스크립트는 인스턴스 이름 뒤 대괄호 안에 하나 이상의 값을 작성함으로써 타입의 인스턴스에 퀴리 및 접근할 수 있다
서브스크립트 문법은 인스턴스 메소드 문법, 계산 프로퍼티 문법과 유사
subscript 키워드와 함께 정의하고, 인스턴스 메소드와 같이 하나 이상의 매개 변수와 반환 값을 지정
인스턴스 메소드와 달리 서브스크립트는 읽기 전용으로 할 수도 있고, 읽기와 쓰기가 모두 되도록 할 수도 있다
계산 프로퍼티에서 사용한 방법과 유사하게 게터와 세터에 의해 작동

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

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

newValue의 타입은 서브스크립트의 반환 값과 동일
계산 프로퍼티처럼, 세터에 newValue 파라미터를 특정하지 않으면 기본 매개 변수인 newValue가 세터에 제공
읽기 전용 서브스크립트는 읽기 전용 계산 프로퍼티처럼,
get 키워드를 제거함으로써 간단하게 선언

// 정수의 n 곱셈 테이블을 표현하는 TimesTable 구조체
struct TimesTable {
    let multiplier: Int
    // 읽기 전용 서브스크립트를 구현
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}

// 인스턴스의 승수 매개변수에 사용할 값으로 구조의 이니셜라이저에 3의 값을 전달
let threeTimesTable = TimesTable(multiplier: 3)

print("six times three is \(threeTimesTable[6])")
// Prints "six times three is 18"
// 서브스크립트를 호출하여 threeTimesTable 인스턴스에 쿼리 및 접근 가능

n-times-table은 고정된 수학적 규칙을 기반으로 구성
threeTimesTable[index]을 new value로 설정하는 것은 적절하지 않으므로,
TimesTable의 서브스크립트는 읽기 전용 첨자로 정의

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

"서브스크립트"의 정확한 의미는 그것이 사용되는 문맥에 달려 있다
서브스크립트는 일반적으로 컬렉션, 리스트, 시퀀스의 멤버 원소에 대한 접근을 축약한 것
특정한 클래스 또는 구조체의 기능을 위해 다양한 방법으로 서브스크립트를 구현 가능

ex. Swift의 딕셔너리 타입은 딕셔너리 인스턴스에 값을 저장하고, 검색하기 위한 서브스크립트 제공
서브스크립트 대괄호 안에 키를 제공하고, 타입에 맞는 값을 서브스크립트에 할당하여 딕셔너리에 값을 설정 가능
또한 서브스크립트로 딕셔너리에 값을 할당할 수도 있다.

// numberOfLegs 변수를 정의
// 세 개의 key-value 쌍을 포함하는 딕셔너리 리터럴로 초기화
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]

// 딕셔너리 구성 후 서브스크립트 할당을 사용하여 "bird"의 문자열 키와 2의 Int 값을 딕셔너리에 추가
numberOfLegs["bird"] = 2

print(numberOfLegs["spider"])
// Prints "Optional(8)"

print(numberOfLegs["dog"])
// Prints "nil"

Swift의 딕셔너리 타입은 옵셔널 타입을 가져와서 반환하는 key-value의 서브스크립트를 구현
모든 키가 값을 가진 것은 아니며, 키에 nil을 할당함으로써 값을 삭제하는 방법을 제공하기 위해 옵셔널 서브스크립트 타입을 사용

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

서브스크립트는 여러 입력 매개 변수를 받을 수 있으며,
해당 입력 매개 변수는 어떤 타입이든 가능하다
서브스크립트는 어떤 타입의 값이든 반환 가능하다

함수처럼 서브스크립트는 다른 개수의 매개 변수를 받을 수도 있고,
기본 값을 설정할 수도 있다
하지만, 인아웃 매개 변수는 사용 불가

클래스와 구조체는 필요한 만큼 많은 서브스크립트를 제공 가능
값(들)의 타입을 기반으로 적당한 서브스크립트가 추론되며,
이러한 다중 서브스크립트 정의를 서브스크립트 오버로딩(subscript overloading)이라 한다
ex. Int / String 타입으로 모두 쿼리 및 접근 가능하도록 구성

한 개의 매개 변수를 취하는 서브스크립트가 보편적이지만,
다수의 매개 변수를 서브스크립트에 정의 가능

ex. Double 값의 2차원 행렬을 표현하는 Matrix 구조체
Matrix 구조체의 서브스크립트는 두 개의 매개 변수를 취한다.

struct Matrix {
    let rows: Int, columns: Int
    var grid: [Double]

    // rows와 columns 두 매개 변수를 취하는 initializer를 제공
    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        // Double 타입의 값을 저장하는 rows * columns 크기의 배열을 생성
        // 행렬 각 위치의 초기 값은 0.0
        grid = Array(repeating: 0.0, count: rows * columns)
    }

    // 초기화에서 지정한 인덱스 영역을 벗어났는지 확인하는 메서드
    func indexIsValid(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }

    // 게터와 세터는 row와 column이 유효한지 확인하기 위한 assertion을 포함
    // assertion을 보조하기 위해 Matrix 구조체는 indexIsValid(row:column:) 메서드를 포함
    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
        }
    }
}

// 적당한 행과 열 개수를 넣어서 새로운Matrix 인스턴스를 생성
var matrix = Matrix(rows: 2, columns: 2)

// 행열의 값은 쉼표로 구분된 서브스크립트에 행, 열 값을 넣어서 할당 가능
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2

let someValue = matrix[2, 2]
// This triggers an assert, because [2, 2] is outside of the matrix bounds.

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

인스턴스 서브스크립트는 특정 타입의 인스턴스에서 호출하는 서브스크립트
타입 자체에서 호출하는 서브스크립트 역시 정의할 수 있는데,
이를 타입 서브스크립트(type subscript)라 한다

static 키워드를 subscript 키워드 앞에 작성하여 타입 서브스크립트를 구성 가능
클래스의 경우, 자식 클래스가 부모 클래스의 서브스크립트 구현의 오버라이딩을 허용하기 위해 class 키워드를 사용할 수 있다

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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant