타입 체크와 캐스팅

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이다.

results matching ""

    No results matching ""