doc: https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html
Opaque Types
Opaque Types
을 사용한 fuction이나 method는 리턴되는 값의 타입에 대한 정보를 숨기는 타입으로 반환된다.- 함수의 반환 타입으로 구체적인 타입을 제공하지 않고, 반환 값이 채택하는 프로토콜로 묘사된다.
- 프로토콜 타입을 반환하는 것과 다르게
Opaque Types
은 타입 정보를 보존한다.
=> 컴파일러는 타입 정보에 접근할 수 있지만, 모듈의 클라이언트는 그렇지 않다.
Opaque Type
을 사용하지 않을 시
protocol Weapon {
func attack()
}
struct NoTypeWeapon: Weapon {
func attack() {
// Attck With No Type
}
}
let noTypeWeapon = NoTypeWeapon()
Weapon 프로토콜을 정의하고 테스트에 사용할 무타입 무기를 만든다.
아직까지 이상한 점은 없다
이어서 Weapon을 컨펌하는 속성 타입 무기를 만들었다.
struct IceTypeWeapon<T: Weapon>: Weapon {
var weapon: T
func attack() {
// Attck With Ice Type
}
}
struct FireTypeWeapon<T: Weapon>: Weapon {
var weapon: T
func attack() {
// Attck With Fire Type
}
}
let iceTypeWeapon = IceTypeWeapon(weapon: noTypeWeapon)
let fireTypeWeapon = FireTypeWeapon(weapon: noTypeWeapon)
타입이...아주 보기 싫게 나온다..
(IceTypeWeapon이면 좋겠지만 IceTypeWeapon이라고 나옴)
흠...
마지막으로 Elementweapon을 두개 합친 듀얼 타입 무기를 만들었다.
struct DualTypeWeapon<T: Weapon, U: Weapon>: Weapon {
var firstWeapon: T
var secondWeapon: U
func attack() {
// Attck With Dual Type
}
}
let dualTypeWeapon = DualTypeWeapon(
firstWeapon: iceTypeWeapon,
secondWeapon: fireTypeWeapon
)
오마이갓... 이게 무슨 타입인지.. 실제 개발할때 저런 타입을 마주한다면 상당히 화가날 것 같다...
Opaque Type
을 사용 시
어떤 Weapon이든 사용처에서는 attack 기능이 중요하지, 어떤 타입인지는 저렇게 자세하게 알 필요가 없을테니Opaque Type
을 사용하여 디테일한 정보를 숨기고 Weapon으로 접근할 수 있게 해보자.
func iceType<T: Weapon>(_ weapon: T) -> some Weapon {
return IceTypeWeapon(weapon: weapon)
}
func fireType<T: Weapon>(_ weapon: T) -> some Weapon {
return FireTypeWeapon(weapon: weapon)
}
func makeDualTypeWeapon<T: Weapon, U: Weapon>(first: T, second: U) -> some Weapon {
return DualTypeWeapon(firstWeapon: first, secondWeapon: second)
}
let iceWeapon = iceType(noTypeWeapon)
let fireWeapon = fireType(noTypeWeapon)
let opaqueTypeWeapon = makeDualTypeWeapon(
first: iceTypeWeapon,
second: fireTypeWeapon
)
opaqueTypeWeapon.attack()
generic과 opaque type을 사용하여 반환 타입을 랩핑하였다.
위에서 만든 dualTypeWeapon
와 동일한 DualTypeWeapon
이지만, opaqueTypeWeapon
는 불필요한 타입 정보를 제거하면서 Weapon 타입에 대한 정보만 남기고, Weapon의 기능을 사용할 수 있게 되었다.
Protocol Type
과 Opaque Type
차이점
(refer을 나타내다로 해석했는데.. 묘사한다? 라는 표현이 더 어울리려나...)
Opaque Type
을 반환하는 것은Protocol Type
를 반환하는 것과 매우 유사하지만, 타입의 정보를 보존하는지 여부에 따라 다르다.Opaque Type
은 함수 호출자가 구체적으로 어떤 타입을 볼 수 없지만, 하나의 특정 타입을 나타낸다.
(some Weapon
을 반환하면 호출자가 구체적으로 어떻게 구성된 Weapon인지는 모르지만, Weapon이라는 특정 타입으로 사용할 수 있다.)Protocol Type
은 해당 protocol을 준수하는 모든 타입을 나타낼 수 있다.- 일반적으로
Protocol Type
을 사용하면 기본 타입에 대해 더 많은 유연성을 제공하는 반면,Opaque Type
을 사용하면 기본 타입에 대해 더 강력한 보장을 할 수 있다. Protocol Type
을 반환하는것과 다르게 모든 반환 값의 유형이 동일해야한다
예제 코드에서 함수의 반환 타입을 Opaque Type
에서 Protocol Type
로 변경해보자.
우선 테스트를 위해 Weapon protocol 에 ==
를 구현해두자.
extension Weapon {
static func == (lhs: Self, rhs: Self) -> Bool {
// some logic
return true
}
}
Opaque Type 사용
func iceType<T: Weapon>(_ weapon: T) -> some Weapon {
return IceTypeWeapon(weapon: weapon)
}
func fireType<T: Weapon>(_ weapon: T) -> some Weapon {
return FireTypeWeapon(weapon: weapon)
}
let firstIceWeapon = iceType(noTypeWeapon)
let secondIceWeapon = iceType(noTypeWeapon)
print(firstIceWeapon == secondIceWeapon)
// result: true
let firstWeapon = iceType(noTypeWeapon)
let secondWeapon = fireType(firstWeapon)
// some Weapon 으로 반환 받은 값을 또 다른 Weapon 으로 넘길 수 있음.
Protocol Type 사용
func iceType<T: Weapon>(_ weapon: T) -> Weapon {
return IceTypeWeapon(weapon: weapon)
}
func fireType<T: Weapon>(_ weapon: T) -> Weapon {
return FireTypeWeapon(weapon: weapon)
}
let firstIceWeapon = iceType(noTypeWeapon)
let secondIceWeapon = iceType(noTypeWeapon)
secondIceWeapon.attack() // 프로토콜의 인터페이스는 사용 가능
print(firstIceWeapon == secondIceWeapon)
// error 발생, Binary operator '==' cannot be applied to two 'Weapon' operands (1)
let firstWeapon = iceType(noTypeWeapon)
let secondWeapon = fireType(firstWeapon)
// error 발생, Protocol 'Weapon' as a type cannot conform to the protocol itself (2)
(1) Opaque Type
과 다르게 Protocol Type
으로 반환하게 되면, 프로토콜의 인터페이스는 사용 가능하지만, 해당 타입에 대한 정보를 이용할 수가 없다.
(2) 프로토콜 타입으로 반환 받은 프로토콜 타입의 'Weapon'은 해당 프로토콜을 채택하지 않은 것으로 간주되어 에러 발생
'iOS > Swift' 카테고리의 다른 글
[Swift] 구조체(struct)와 클래스(class)의 차이 정리 (0) | 2023.03.01 |
---|---|
WCSession / WCSessionDelegate 정리 (0) | 2023.02.28 |
UICollectionView 섹션에 배경 색상을 적용하기 (0) | 2023.02.23 |