Page 29 -
P. 29
val list = listOf(1, 2, 3) // List<Int>
list is List<Number> // OK
// error: cannot check for instance of erased type: List<String>
list is List<String>
원소 타입에는 관심이 없고 어떤 값이 리스트인지만 확인하고 싶다면 어떨까? 코틀린의 제네릭
타입은 항상 타입 인자를 포함해야 하기 때문에 이런 경우에도 List만 쓸 수는 없다. 올바른 검사
는 다음과 같다.
list is List<*>
map is Map<*, *>
여기서 *는 기본적으로 알지 못하는 타입을 뜻하며, 타입 인자 하나를 대신한다. 이 구문은 실제 9
로는 프로젝션이라는 특별한 경우에 속한다. 프로젝션은 나중에 설명하겠다. 제네릭스
어떤 경우에는 컴파일러가 타입 검사가 맞는지 알 수 있는 정보를 충분히 갖고 있어서 경고/오
류를 표시하지 않을 수도 있다. 다음 예제에서 타입 검사는 근본적으로 List<Int>나 Collection
<Int> 같은 타입 파라미터의 구체적인 타입과 무관하게 List와 Collection 인터페이스의 관계에
따라 결정된다.
val collection: Collection<Int> = setOf(1, 2, 3)
if (collection is List<Int>) {
println("list")
}
어떤 값을 *가 아닌 타입 인자가 붙은 제네릭 타입으로 캐스트하는 것이 허용되지만, 이런 캐스트
에는 위험이 따르기 때문에 항상 경고가 표시된다. 이런 식으로 타입을 캐스팅하면 제네릭스의 한
계를 우회할 수는 있지만, 런타임까지 실제 타입 오류를 미루는 효과가 있다. 예를 들어 다음 두
식은 모두 경고가 표시되면서 컴파일되지만, 첫 번째 식은 정상적으로 끝나는 반면 두 번째 식은
예외가 발생한다.
val n = (listOf(1, 2, 3) as List<Number>)[0] // OK
val s = (listOf(1, 2, 3) as List<String>)[0] // java.lang.ClassCastException
후자의 예외는 리스트 원소의 값(이 경우에는 Int)을 String 타입의 (정적으로 알려진) 변수에 대
입하기 때문에 생긴다.
369
Kotlin_05.indd 369 2022-02-15 오후 4:08:04