Studying/Kotlin

[kotlin] 스마트 캐스트

강옌니 2024. 2. 29. 05:01

is and !is operators

if (obj is String) {
    print(obj.length)
}

if (obj !is String) { // Same as !(obj is String)
    print("Not a String")
} else {
    print(obj.length)
}

 

is를 통해서 지정된 객체 유형에 맞는지 검사를 수행한다.


Smart casts

 

fun demo(x: Any) {
    if (x is String) {
        print(x.length) // x is automatically cast to String
    }
}

 

 is의 대부분의 경우 컴파일러가 명시적 캐스트를 추적해서 필요할때 자동으로 안전한 캐스트를 삽입하기 때문에, 명시적 캐스트 연산자를 사용할 필요가 없다.

 

if (x !is String) return

print(x.length) // x is automatically cast to String

 

 컴파일러가 부정검사가 반환으로 이어지는 경우 캐스트가 안전하다는 것을 알기도 합니다.

 

// x is automatically cast to String on the right-hand side of `||`
if (x !is String || x.length == 0) return

// x is automatically cast to String on the right-hand side of `&&`
if (x is String && x.length > 0) {
    print(x.length) // x is automatically cast to String
}

 

 조건식 안 && , ||에서도 is가 사용되어서 스마트 캐스트가 사용된다.

 

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

 

 스마트 캐스트는 when 표현식이나 while 루프에서도 작동한다.

 

그런데 컴파일러가 타입 검사와 사용간에 변수가 변경되지 않는다고 보장할 수 없으면 스마트 캐스트가 작동하지 않는다. 다음 규칙에 따라 적용할 수 있다.

 

  • val 로컬 변수:  항상 가능하다.
  • val 프로퍼티 : 프로퍼티가 private 도는 internal인 경우, 또는 프로퍼티가 선언되고 있는 같은 모듈에서 체크를 한 경우에는 open 프로퍼티나 getter를 가지는 프로퍼티에는 적용할 수 없다.
  • var 로컬 변수: 검사와 사용 할 사이에 수정되지 않고, 그것을 수정하는 람다에 캡쳐되지 않는 경우에 가능
    • [캡쳐란 ?]
      • 람다 표현식 내부에서 그 변수를 사용할 수 있다는 의미이다.
      • 캡쳐된 변수를 마치 자신의 변수처럼 사용할 수 있고, 람다 표현식이 생성되는 시점의 변수의 값을 기억하고 이를 활용할 수 있게 한다.
  • var 프로퍼티 - (변수가 다른 코드에 의해 언제든지 수정가능하므로) 안된다.

 

[여기서 로컬변수와 프로퍼티란?]

  1. 로컬 변수(Local Variables): 로컬 변수는 특정 함수나 메소드 내에서만 사용되는 변수이다. 이 변수들은 해당 함수나 메소드가 호출될 때 생성되고, 작업이 완료되면 사라진다. 즉, 그 범위는 함수나 메소드 내로 제한된다. 다른 함수나 메소드에서는 이 변수에 접근할 수 없다.
  2. 프로퍼티(Properties): 프로퍼티는 클래스, 구조체, 열거형 내부에 위치한 변수이다. 이들은 해당 객체의 상태를 나타내는데 사용되며, 객체의 외부에서도 접근할 수 있다. 프로퍼티는 getter와 setter 메소드를 통해 값을 읽고 쓸 수 있으며, 이를 통해 값을 안전하게 조작하거나 검증할 수 있다. 

 요약하자면, 로컬 변수는 일시적인 데이터 저장과 함수 내에서의 데이터 조작에 사용되며, 프로퍼티는 객체의 상태를 표현하고 외부에서도 접근 가능하도록 설계되어 있습니다.

 

“Unsafe" cast operator

 

val x: String = y as String

 

 이 코드는 'y'를 String으로 강제 변환하여 'x'에 저장하려고 한다.

 'y'가 String이 아니라면 이 코드는 ClassCastException을 발생시킬 것이다. 또한, 'y'가 null이라면 NullPointerException을 발생시킬 것이다.

 

val x: String? = y as String?

 이 코드는 'y'를 String으로 강제 변환하거나 'y'가 null이라면 null을 'x'에 저장하려고 한다.

 ‘y’가 null일때의 오류는 해결했지만, 하지만 여전히 'y'가 String이 아니라면 이 코드는 ClassCastException을 발생시킬 것이다.

 

"Safe" (nullable) cast operator

 

val x: String? = y as? String

 

 

 따라서 as? 을 통해서 예외발생으로 인한 오류를 방지한다.