타입 체크와 캐스팅
is 와 !is 연산자
is
와 !is
연산자를 사용하여 런타임에 객체가 주어진 타입인지 확인할 수 있다.
if (obj is String) {
print(obj.length)
}
if (obj !is String) { // !(obj is String) 와 동일
print("Not a String")
}
else {
print(obj.length)
}
스마트 캐스트
Kotlin에서 컴파일러가 불변 값에 대해 is
-검사를 추적하여 필요할 때 자동으로 (안전하게) 캐스팅을 추가하기 때문에, 많은 경우 명시적 캐스팅 연사자를 사용할 필요가 없다
fun demo(x: Any) {
if (x is String) {
print(x.length) // x 를 자동으로 String으로 캐스팅한다
}
}
컴파일러가 부정 검사로 return 하는 경우, 안전하게 캐스트된다는 것을 안다.
if (x !is String) return
print(x.length) // x 를 자동으로 String으로 캐스팅한다
&&와 ||의 우에서도 안전하게 캐스팅된다.
// x 는 `||`의 오른쪽에 있는 String으로 자동 캐스팅된다.
if (x !is String || x.length == 0) return
// x 는 `&&`의 오른쪽에 있는 String으로 자동 캐스팅된다.
if (x is String && x.length > 0) {
print(x.length) // x is automatically cast to String
}
스마트 캐스트는 when 표현식과 while-loop 에서도 동작한다
when (x) {
is Int -> print(x + 1)
is String -> print(x.length + 1)
is IntArray -> print(x.sum())
}
컴파일러가 타입 검사와 사용간에 변수가 변경되지 않는다고 보장할 수 없으면 스마트 캐스트가 작동하지 않는다. 다음 규칙에 따라 적용할 수 있다.
- val 로컬 변수 - 항상 가능
- val 프로퍼티 - 프로퍼티가 private 도는 internal인 경우, 또는 프로퍼티가 선언되고 있는 같은 모듈에서 체크를 한 경우. open 프로퍼티나 getter를 가지는 프로퍼티에는 적용할 수 없다
- var 로컬 변수 - 검사와 사용 사이에 수정되지 않고, 그것을 수정하는 람다에 캡쳐되지 않는 경우에 가능
- var 프로퍼티 - (변수가 다른 코드에 의해 언제든지 수정가능하므로) never
"안전하지 않은" 캐스트 연산자
일반적으로 캐스트 연산자는 캐스트 불가능시 예외를 발생한다. 그래서 이것을 안전하지 않다라고 부른다. Kotlin 의 안전하지 않은 캐스트는 중위 연사자 as 로 한다. (연산자 우선 순위 참조)
val x: String = y as String
String
타입은 nullable이 아니므로 null 을 String 으로 형변환할 수 없다. 즉, y
가 null 인 경우, 위의 코드는 예외를 발생한다. Java 의 캐스트 의미를 맞추기 위해 오른쪽을 nullable 타입을 사용해야 한다.
val x: String? = y as String?
"안전한" (nullable) 캐스트 연산자
예외가 발생하지 않도록 하려면 안전한 캐스트 연산 as? 를 사용할 수 있다. 실패시 null 을 반환한다.
val x: String? = y as? String
as? 의 우측 연산자가 non-null 타입 String
임에도 불구하고 변환 결과가 nullable이다.