[Kotlin] 5-4. 타입 검사와 변환

타입 검사와 변환: ‘is’와 ‘as’

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)
}

스마트 타입 변환

코틀린에서는 많은 경우 명시적인 타입 변환 연산이 필요 없다. 왜냐면 컴파일러가 불변 값에 대해 is검사와 명시적 타입 변환을 추적해서 자동으로 필요한 곳에 (안전한) 타입 변환을 넣어주기 때문이다

fun demo(x: Any) {
  if(x is String) {
    print(x.length)  // x를 자동으로 String으로 타입 변환
  }
}

!is 검사를 통해 리턴할 경우 컴파일러는 타입 변환을 안전하게 할 수 있다는 것을 알고, 자동으로 타입 변환을 추가한다

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를 자동으로 String으로 타입 변환

이런 스마트 타입 변환은 when식과 while루프에서도 동작한다

when(x) {
  is Int -> print(x + 1)
  is String -> print(x.length + 1)
  is IntArray -> print(x.sum())

변수 검사와 사용 사이에 변수가 바뀌지 않는다는 것을 컴파일러가 확신할 수 없으면 스마트 타입 변환이 동작하지 않는다. 구체적으로 다음 규칙에 따라 스마트 타입 변환을 적용한다

val x: String = y as String

x는 null이 가능 하지 않기 때문에 null을 String타입으로 변환할 수 없다. 예를 들어, y가 null이면 위 코드는 익셉션을 던진다. 자바의 변환 세만틱에 맞추려면, 다음과 같이 변환 연산자의 오른쪽에 null 가능 타입이 와야 한다

val x: String? = y as String?

“안전한” (nullable)타입 변환 연산자

익셉션이 발생하는 것을 피하려면 안전한 타입 변환 연산자인 as?를 사용할 수 있다. 이 연산자는 실패시 null 을 리턴한다

val x: String? = y as? String

as?의 오른쪽이 null이 아닌 String타입이지만 타입 변환 결과는 null 가능 타입이다