🔥 서브스크립트의 다양한 옵션

539자
7분

서브스크립트는 입력 매개변수를 원하는 만큼 가질 수 있고, 이 입력 매개변수는 어떤 타입이든 될 수 있어요. 또한 서브스크립트는 어떤 타입이든 값을 반환할 수 있죠.

함수처럼 서브스크립트도 가변 매개변수를 사용할 수 있고, 매개변수의 기본값을 제공할 수 있어요. 이는 Variadic ParametersDefault Parameter Values에서 다뤘던 내용이죠. 그러나 함수와 달리 서브스크립트는 입출력 매개변수를 사용할 수 없답니다.

클래스나 구조체는 필요한 만큼 많은 서브스크립트 구현을 제공할 수 있어요. 서브스크립트가 사용되는 시점에 서브스크립트 대괄호 안에 포함된 값의 타입에 기반하여 적절한 서브스크립트가 유추될 거예요. 이렇게 여러 서브스크립트를 정의하는 것을 서브스크립트 오버로딩(subscript overloading)이라고 해요.

서브스크립트가 단일 매개변수를 사용하는 것이 가장 일반적이지만, 타입에 적합하다면 여러 매개변수를 사용하는 서브스크립트를 정의할 수도 있죠. 다음 예제는 Double 값의 2차원 행렬을 나타내는 Matrix 구조체를 정의하고 있어요. 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)
    }
 
    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
        }
    }
}
swift

Matrixrowscolumns라는 두 개의 매개변수를 사용하는 이니셜라이저를 제공해요. 이 이니셜라이저는 rows * columns 개의 Double 타입 값을 저장할 수 있는 충분한 크기의 배열을 생성하죠. 행렬의 각 위치는 초기값으로 0.0을 가집니다. 이를 위해 배열의 크기와 0.0이라는 초기 셀 값을 배열 이니셜라이저에 전달하여 올바른 크기로 새 배열을 생성하고 초기화하는 거예요. 이 이니셜라이저는 Creating an Array with a Default Value에서 더 자세히 설명되어 있어요.

적절한 행과 열의 개수를 이니셜라이저에 전달하여 새로운 Matrix 인스턴스를 생성할 수 있죠.

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

위 예제는 2개의 행과 2개의 열을 가진 새로운 Matrix 인스턴스를 생성해요. 이 Matrix 인스턴스의 grid 배열은 행렬을 왼쪽 위에서 오른쪽 아래로 읽은 순서대로 평평하게 펼친 버전이에요.

lecture image

행렬의 값은 쉼표로 구분된 행과 열 값을 서브스크립트에 전달하여 설정할 수 있습니다.

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

위 두 문장은 서브스크립트의 setter를 호출하여 행렬의 오른쪽 위 위치(row0이고 column1인 위치)에 1.5 값을 설정하고, 왼쪽 아래 위치(row1이고 column0인 위치)에 3.2 값을 설정하고 있어요.

lecture image

Matrix 서브스크립트의 getter와 setter는 모두 서브스크립트의 rowcolumn 값이 유효한지 확인하기 위한 assertion을 포함하고 있어요. 이러한 assertion을 돕기 위해, MatrixindexIsValid(row:column:)이라는 유용한 메서드를 포함하고 있는데, 이 메서드는 요청된 rowcolumn이 행렬의 범위 내에 있는지 확인해 줍니다.

func indexIsValid(row: Int, column: Int) -> Bool {
    return row >= 0 && row < rows && column >= 0 && column < columns
}
swift

만약 행렬의 범위를 벗어난 서브스크립트에 접근하려고 하면 assertion이 트리거 됩니다.

let someValue = matrix[2, 2]
// 이는 [2, 2]가 행렬의 범위를 벗어났기 때문에 assertion을 트리거합니다.
swift

이처럼 서브스크립트는 다양한 매개변수 옵션을 제공하여 우리가 원하는 방식으로 유연하게 설계할 수 있어요. 단일 매개변수부터 여러 매개변수, 기본값, 가변 매개변수 등을 활용하면 코드의 가독성과 효율성을 높일 수 있겠죠?

또한 필요에 따라 여러 개의 서브스크립트를 오버로딩하여 다양한 상황에 맞는 동작을 구현할 수도 있답니다. 예를 들어, 정수형 인덱스를 받는 서브스크립트와 문자열 키를 받는 서브스크립트를 함께 정의하여 배열과 딕셔너리 방식의 접근을 모두 제공할 수 있을 거예요.