본 글은 야곰의 스위프트 프로그래밍: Swift5 교재를 토대로 공부한 내용과 찾아본 내용을 요약한 것입니다.
반환 타입에 불명확 타입(Opaque Types)을 사용하면 반환할 타입의 정확한 타입을 알려주지 않은채로 반환하겠다는 것을 의미합니다.
프로퍼티나 서브스크립트의 선언 혹은 함수의 반환 타입 위치에 프로토콜을 쓰면서 앞에 some을 붙이면, '이 프로토콜을 준수하는 어떤 타입 중에 하나일 것은 분명하다'는 뜻입니다 언뜻 보면 '제네릭 아닌가?'라는 생각이 들 수 있지만 잘 생각하면 많이 다릅니다. 제네릭은 정의해줄 때 정확히 어떤 타입이 들어올지 모르는 상태로 플레이스 홀더를 만들어주는 반면, 불명확 타입은 반대로 외부에서 어떤 타입이 나에게 반환될지 모릅니다. 즉, 제네릭은 외부에서 타입을 지정해 주는 것이고, 불명확 타입은 내부에서 타입을 정해서 내보내게 되는데, 밖에서는 정확히 어떤 타입인지 몰라도 쓸 수 있는 것입니다. 그래서 역제네릭 타입(Reverse Generics Types)라고 표현하기도 합니다.
여러 종류의 피규어를 임의로 배출하는 뽑기 기계가 있다고 가정하고 예시를 들어보겠습니다.
// 뽑기 상품 프로토콜 정의
// 포장된 상품을 표현
protocol WrappedPrize {
associatedtype Prize
var wrapColor: String! { get } // 포장 색상
var prize: Prize! { get } // 실제 상품
}
// 실제 포장된 상품
protocol Gundam { }
protocol Pokemon { }
struct WrappedGundam: WrappedPrize {
var wrapColor: String!
var prize: Gundam!
}
struct WrappedPokemon: WrappedPrize {
var wrapColor: String!
var prize: Pokemon!
}
// 뽑기 기계. 임의의 포장된 상품을 내준다.
struct PrizeMachine {
func dispenseRandomPrize() -> WrappedPrize {
return WrappedGundam()
}
}
// WrappedPrize는 제네릭 타입 제약이 있어야만 사용할 수 있는 타입이기 때문에 WrappedPrize 자체 만으로는 반환 타입이 될 수 없다고 오류를 뱉어냅니다.
// 뽑기 기계 구조체 개선
struct PrizeMachine {
func dispenseRandomPrize() -> some WrappedPrize {
return WrappedGundam()
}
}
let machine: PrizeMachine = PrizeMachine()
let wrappedPrize = machine.dispenseRandomPrize()
이처럼 외부에서 정확한 타입은 알 수 없지만, 해당 프로토콜을 준수하는 어떤 타입인가를 반환한다는 약속을 불명확 타입으로 표현할 수 있습니다. 불명확 타입은 함수(메서드)의 반환 타입뿐만 아니라 프로퍼티나 서브스크립트의 타입에도 사용할 수 있습니다.