열 번째, 타입 검사와 캐스트입니다.
코틀린에서는 특정 객체의 타입을 확인하기 위해 타입 검사를 할 수 있습니다. 타입 캐스트는 객체를 특정한 타입으로 변환하는 것을 말합니다.
특별히 제네릭의 타입 검사와 캐스트를 공부하고 싶은 경우에는 제네릭 타입 검사와 캐스트를 보시면 됩니다.
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) {
// 위의 x is String에서 String으로 확인된 경우이므로,
// String으로 명시적으로 캐스트하지 않아도 자동으로 캐스트됩니다.
print(x.length)
}
}
컴파일러는 부정형 타입 확인 반환하는 경우에 대해서도 하위에서 자동 캐스트 하는 것이 안전하다는 것을 알 정도로 영리합니다.
if (x !is String) return
print(x.length) // x is automatically cast to String
&& 나 !! 연산자에 대해서도 적절히 판단합니다.
// ||는 오른쪽 부분이 참이면 왼쪽 부분까지 평가하지 않지만
// 오른쪽 부분이 거짓이면, x가 String이라는 뜻이 되고
// 이를 컴파일러가 인지가 오른쪽 부분에서 x를 String으로 자동으로 캐스트합니다.
if (x !is String || x.length == 0) return
// &&은 왼쪽 부분이 참일 경우에만 오른쪽 부분을 평가하므로
// 오른쪽 부분을 평가한다는 것은 x가 String이라는 뜻이므로
// 컴파일러는 이를 인지하고, 오른쪽 부분에서 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 지역 변수 | 지역 위임 프로퍼티를 제외하고 항상 |
val 프로퍼티 | private/internal 프로퍼티거나 프로퍼티가 선언된 같은 모듈내에서 타입을 확인한 경우. 스마트 캐스트는 open 프로퍼티나 맞춤화된 게터가 있는 프로퍼티에는 동작하지 않음. |
var local 변수 | 변수 검사 시점과 사용 시점에 값이 변경되지 않으며, 해당 변수의 값을 변경하는 람다에 캡처되지도 않고, 로컬 위임 프로퍼티가 아닌 경우. |
var 프로퍼티 | 결코 적용되지 않음. var 프로퍼티는 다른 코드에 의해서 언제든지 변경될 수 있기 때문에 불가. |
"안전하지 않은(Unsafe)" 캐스트 연산자
보통, 캐스트 연산자는 캐스트가 불가한 경우 예외를 던집니다. 그래서, 이를 안전하지 않다(unsafe)고합니다. 코틀린에서 안전하지 않은 캐스트는 as 중위 연산자로 수행됩니다.
unsafe는 '위험한'으로도 번역될 수 있습니다만, 위험이라는 단어를 쓰면 절대 써서는 안 될 거 같은 느낌이 있어서 '안전하지 않은'으로 번역했습니다. 실무에서는 그냥 '언세이프'로 바로 얘기하는 경우도 많을 것으로 생각됩니다.
val x: String = y as String
String 타입은 널 가능하지 않기 때문에 null은 String으로 캐스트 될 수 없습니다. y가 null이면, 위에 있는 코드는 예외를 던집니다. 이러한 코드를 null 값이 캐스트 되도록 수정하려면, 캐스트의 오른쪽 부분에 널 가능한 타입을 사용합니다(당연히 왼쪽 부분에도 사용합니다).
val x: String? = y as String?
"안전한" (널 가능한) 캐스트 연산자
예외를 피하기 위해서, 캐스트에 실패하는 경우 null을 반환하는 안전한 캐스트 연산자인 as?를 사용합니다.
val x: String? = y as? String
as?의 오른쪽 부분은 널 가능한 타입이 아니지만 캐스트에 실패하는 경우 null을 반환하므로 캐스트 결과는 널 가능합니다.
'Kotlin' 카테고리의 다른 글
공식 문서로 배우는 코틀린 - 12. Packages and imports (0) | 2024.03.07 |
---|---|
공식 문서로 배우는 코틀린 - 11. Control flow (0) | 2024.03.06 |
공식 문서로 배우는 코틀린 - 9. Basic Types - Arrays (1) | 2024.03.05 |
공식 문서로 배우는 코틀린 - 8. Basic Types - Strings (0) | 2024.03.02 |
공식 문서로 배우는 Kotlin - 7. Basic Types - Characters (0) | 2024.03.02 |