표현식이 변환할 Type과 호환된다면, 변환할 Type으로 캐스팅된 인스턴스를 리턴한다. 상속 관계인 업캐스팅과 다운 캐스팅에서 사용한다.
class Cafe {
let menu: String
init(menu: String) {
self.menu = menu
}
}
class Latte: Cafe { }
class Tea: Cafen { }
let order: [Cafe] = [
Latte.init(menu: "green tea latte"),
Tea.init(menu: "EarlGray"),
Tea.init(menu: "peppermint")
]
Latte와 Tea라는 타입의 인스턴스가 들어갈 수 있는 이유는 업캐스팅을 했기에 가능. Latte와 Tea란 클래스는 서로 다른 타입의 클래스 이지만 부모 클래스(Cafe)가 같다. 둘의 슈퍼 클래스가 Cafe으로 동일하기 때문에, 이 둘을 Cafe란 클래스로 업캐스팅 해서 묶어버린 것.
class Cafe {
let name: String = "Starbucks"
}
class Latte: Cafe {
let menu: String = "green tea latte"
}
class Shot: Cafe {
let shots: Int = 1
}
let cafe = Latte.init() as Cafe
👉 Latte 타입의 인스턴스를 생성하지만, 이를 Cafe 타입으로 업캐스팅해서 cafe에 저장하겠다.
Latte란 인스턴스가 온전히 메모리에 올라감. cafe가 Latte란 서브 클래스를, Cafe란 슈퍼클래스 타입으로 참조하는 업캐스팅을 한 것이기 때문에, cafe의 접근 범위가 'Cafe' 멤버로 한정된다.
cafe.name // Starbucks
cafe.menu // Value of type 'Cafe' has no member 'menu'
이렇게, Cafe 클래스의 멤버인 name엔 접근할 수 있지만,
서브 클래스 Latte의 멤버인 menu엔 접근할 수 없다. 서브 클래스의 인스턴스를 슈퍼 클래스의 타입으로 참조하는 것을 업캐스팅이라고 함
슈퍼 클래스 인스턴스를 서브 클래스의 타입으로 참조한다. 업캐스팅된 인스턴스를 다시 원래 서브 클래스 타입으로 참조할 때 사용한다.
as?와 as!연산자를 이용해 어떤 타입의 인스턴스인지 확인할 수 있다.
as?는 특정 타입이 맞는지 확신할 수 없을때 사용하고, as!는 특정 타입이라는 것이 확실한 경우에 사용한다. 단 as!으로 다운캐스팅을 했는데 지정한 타입이 아니라면 런타임 에러가 발생한다.
Cafe 타입으로 업캐스팅된 cafe 변수를 다시 하위 클래스인 Latte 타입으로 변환해서 넣어 줌.
var latte: Latte = cafe as! Latte
latte.menu // green tea latte
var things: [Any] = []
things.append(1)
things.append(3.5)
things.append("coffee")
things.append(false)
things.append(Cafe.init()))
things.append({ print("Tasty!") })
for thing in things {
switch thing {
case _ as Int:
print("Int Type!")
case _ as Double:
print("Double Type!")
case _ as String:
print("String Type!")
case _ as Cafe:
print("Cafe Type")
case _ as () -> ():
print("Closure Type")
default:
print("something else")
}
}
if var name = name as? String {
name.append("Good!")
}