🔥 컨텍스트 Where 절

389자
5분

Swift에서는 제네릭 타입 제약 조건이 없는 선언의 일부로 제네릭 where 절을 작성할 수 있어요. 이는 이미 제네릭 타입의 컨텍스트에서 작업하고 있을 때 유용하게 사용된답니다.

예를 들어, 제네릭 타입의 서브스크립트나 제네릭 타입의 확장에 있는 메서드에 제네릭 where 절을 작성할 수 있지요. 아래 예제에서 Container 구조체는 제네릭이고, where 절은 이러한 새로운 메서드를 컨테이너에서 사용할 수 있도록 하기 위해 어떤 타입 제약 조건이 충족되어야 하는지를 지정하고 있어요.

extension Container {
    func average() -> Double where Item == Int {
        // 요소들의 합을 저장할 변수
        var sum = 0.0
        // 컨테이너의 모든 요소를 순회하면서
        for index in 0..<count {
            // 각 요소를 Double로 변환하여 합에 더함
            sum += Double(self[index])
        }
        // 합을 요소 개수로 나누어 평균을 구함
        return sum / Double(count)
    }
 
    func endsWith(_ item: Item) -> Bool where Item: Equatable {
        // 컨테이너의 마지막 요소가 주어진 item과 같은지 확인
        return count >= 1 && self[count-1] == item
    }
}
 
let numbers = [1260, 1200, 98, 37]
print(numbers.average())
// "648.75" 출력
print(numbers.endsWith(37))
// "true" 출력
swift

이 예제는 Item 타입이 Int일 때 Containeraverage() 메서드를 추가하고, Item 타입이 Equatable을 준수할 때 endsWith(_:) 메서드를 추가한답니다. 두 함수 모두 원래 Container의 선언에서 제네릭 Item 타입 매개변수에 타입 제약 조건을 추가하는 제네릭 where 절을 포함하고 있죠.

만약 컨텍스트 where 절을 사용하지 않고 이 코드를 작성하려면, 각 제네릭 where 절에 대해 하나씩 두 개의 확장을 작성해야 해요. 위의 예제와 아래의 예제는 동일하게 동작합니다.

extension Container where Item == Int {
    func average() -> Double {
        var sum = 0.0
        for index in 0..<count {
            sum += Double(self[index])
        }
        return sum / Double(count)
    }
}
 
extension Container where Item: Equatable {
    func endsWith(_ item: Item) -> Bool {
        return count >= 1 && self[count-1] == item
    }
}
swift

컨텍스트 where 절을 사용한 버전의 예제에서는 average()endsWith(_:)의 구현이 모두 동일한 확장에 있어요. 각 메서드의 제네릭 where 절은 해당 메서드를 사용할 수 있도록 만들기 위해 충족되어야 하는 요구 사항을 명시하고 있기 때문이죠.

이러한 요구 사항을 확장의 제네릭 where 절로 이동하면 메서드를 동일한 상황에서 사용할 수 있지만, 요구 사항마다 하나의 확장이 필요하게 된답니다.

이렇게 컨텍스트 where 절을 사용하면 관련된 제약 조건을 하나의 확장에 모아서 표현할 수 있어 코드의 가독성과 응집성을 높일 수 있어요. 반면 제약 조건마다 별도의 확장을 작성하는 것은 코드를 분산시켜 오히려 복잡성을 증가시킬 수 있겠죠.

따라서 컨텍스트에 맞게 적절한 방식을 선택하여 제네릭 where 절을 활용한다면, 더욱 간결하고 표현력 있는 코드를 작성할 수 있을 거예요.