Page 28 -
P. 28

class Registry<T> where T : Named, T : Identified {
                   val items = ArrayList<T>()
                 }

               where 절을 클래스 선언 본문 앞에 추가하고 바운드할 타입 목록을 표시한다.

               제네릭스의 문법을 맛봤으니 지금부터는 런타임에 제네릭스의 표현을 어떻게 처리할지 살펴보자.




               9.1.3 타입 소거와 구체화


               앞 예제에서는 타입 파라미터를 사용해 제네릭 선언 안의 변수, 프로퍼티, 함수 타입을 지정하는

               것을 살펴봤다. 하지만 타입 파라미터가 항상 실제 타입을 대신할 수 있는 것은 아니다. 예를 들어
               다음 코드를 살펴보자.

                 fun <T>TreeNode<Any>.isInstanceOf(): Boolean =
                   // error: cannot check for instance of erased type: T
                   data is T && children.all{ it.isInstanceOf<T>() }

               의도는 주어진 트리의 노드나 자식의 노드가 모두 지정한 타입 T를 만족하는지 검사하는 것이다.
               하지만 컴파일러는 data is T라는 식에 오류를 표시한다. 오류가 발생하는 이유는 타입 소거 때

               문이다.
               자바에 익숙하다면 자바 제네릭스에도 비슷한 제약이 있다는 점을 떠올릴 것이다. 이런 제약은 자
               바 제네릭스가 자바 5부터 도입됐기 때문이다. 따라서 새 버전 자바 컴파일러와 가상 머신은 기존

               (자바 5 이전) 코드와의 하위 호환성을 위해 기존 타입 표현 방식을 유지해야 했다. 그 결과 JVM에
               서 타입 인자에 대한 정보는 코드에서 지워지고(그래서 타입 소거라는 용어가 나왔다), 소스코드에
               서 List<String>이나 List<Number>와 같은 타입은 JVM에서 List라는 동일한 타입으로 합쳐진다.

               코틀린은 1.0 버전부터 제네릭스가 있었지만, JVM이 주요 플랫폼이었기 때문에 자바와 같은 타
               입 소거 문제가 생겼다. 런타임에 제네릭 코드는 파라미터 타입의 차이를 인식할 수 없고, 앞에서
               본 data is T와 같은 검사는 기본적으로 아무 의미도 없다. isInstance() 함수가 런타임에 호출될

               때 T가 어떤 타입을 뜻할지 알 방법이 없다. 마찬가지 이유로 제네릭 타입에 대해 is 연산자를 적
               용하는 것도 의미가 없다. 다만 이런 경우에는 컴파일러가 타입 인자와 타입 파라미터가 서로 일
               치하는지를 살펴보고, 그에 따라 경고나 오류를 보고한다.






         368





     Kotlin_05.indd   368                                                                    2022-02-15   오후 4:08:04
   23   24   25   26   27   28   29   30   31   32   33