Generic Type & Opaque Type
some 키워드는 opaque type에 대해 사용한다. opaque 타입은 역 제네릭 타입(reverse generic type) 이라고도 불린다.
- Generic 타입은 구체적인 타입이 무엇인지를 사용하는 호출자 측에서 결정한다.
- Opaque 타입은 구체적인 타입을 피호출자, 즉 함수 내부에서 결정하고, 함수를 사용하는 호출자는 어떤 타입인지 알 수 없다.
- class에는 Generic파라미터를 사용할 수 있지만, 프로토콜에서는 사용할 수 없다.
protocol GiftBox {
associatedtype giftType
var gift: giftType { get }
}
- protocol 에서는 associatedType으로 지정한다.
associatedtype을 가지고 있는 protocol 과 구현체
struct Apple{}
struct Cherry{}
protocol GiftBox {
associatedtype giftType
var gift: giftType { get }
}
struct AppleGiftBox: GiftBox {
var gift: Apple
}
struct CherryGiftBox: GiftBox {
var gift: Cherry
}
- GiftBox 프로토콜은 giftType 을 associatedType으로 가지고 있다.
- associatedtype의 실질적인 타입은 프로토콜을 구현한 AppleGifxBox, CherryGiftBox에서 정해진다.
- AppleGiftBox는 Apple 구조체 타입을 사용
- CherryGiftBox는 Cherry 구조체 타입을 사용
구체적인 타입을 함수 내부에서 결정하는 Opaque Type
class GiftMaker {
func makeGiftBox() -> some GiftBox {
return AppleGiftBox(gift: Apple())
}
func makeCherryGiftBox() -> CherryGiftBox {
return CherryGiftBox(gift: Cherry())
}
}
- makeGiftBox 함수는 GiftBox라는 프로토콜 타입을 리턴한다고 명시한다.
- 함수 내부적으로는 AppleGiftBox를 리턴 하므로, associatedType은 AppleGiftBox의 associatedtype인 Apple 구조체임을 알 수 있다. (makeGiftBox 함수 내부에서 giftType이 Apple로 결정)
- makeGiftBox 를 사용하는 호출자 입장에서는 단지 GiftBox 준수 타입이 리턴된다고만 알 수 있다.
- makeCherryGiftBox 함수는 리턴 타입을 명시적으로 CherryGiftBox로 주었다.
struct Caller {
func call() {
var giftMaker = GiftMaker()
var giftBox = giftMaker.makeGiftBox()
var gift: Any = giftBox.gift
var giftBox2 = giftMaker.makeCherryGiftBox()
var gift2: Cherry = giftBox2.gift
}
}
- 호출자 입장에서는 giftMaker.makeGiftBox 함수가 GiftBox 프로토콜을 준수하는 클래스(구조체)를 리턴한다고만 알 수 있다. 따라서 정확히 어떤 구체적인 클래스(구조체)인지 알 수 없고, 그에 따라 gift 의 타입인 giftType이 Apple인지, Cherry인지 무엇인지를 정확히 알 수 있는 방법이 없다.. 그래서 some 키워드가 필요한 것이다.
- giftMaker.makeCherryGiftBox는 CherryGiftBox 구조체를 리턴하므로, 정확한 연관타입인 Cherry를 알 수 있고, 따라서 some이 필요 없다.
참고