-
24장 - 제네릭 타입과 variance 한정자를 활용하라Kotlin/Effective Kotlin 요약 2023. 3. 7. 00:01728x90
불공변성(invariant)이란?
제네릭 타입으로 만들어지는 타입이 서로 관련성이 없다는 의미입니다.
예를 들어 다음 제네릭들은 서로 어떠한 관련성도 갖지 않습니다.
- Cup<Int>
- Cup<Number>
- Cup<Any>
- Cup<Nothing>
공변성(covariant)이란?
어떤 관련성을 원할 경우 out 또는 in이라는 variance 한정자를 붙일 수 있습니다.
out은 타입 파라미터를 공변성으로 만듭니다.
A가 B의 서브타입일때 Cup<A>가 Cup<B>의 서브타입이라는 의미입니다.
in은 반대 의미입니다.
타입 파라미터를 contravariant(반변성)으로 만듭니다.
A가 B의 서브타입일때 Cup<A>가 Cup<B>의 슈퍼타입이라는 의미입니다.
코틀린에서 함수와 variance
코틀린 함수 타입의 모든 파라미터 타입은 contravariant입니다.
또한 모든 리턴 타입은 covariant입니다.
(Int) -> Any 타입의 함수는 다음과 같이도 동작합니다.
(Int) -> Number
(Number) -> Any
(Number) -> Number
(Number) -> Int
variance 한정자의 안정성
자바의 배열은 convariant입니다.
이로 인해 컴파일 중에 아무런 문제는 없지만, 런타임 오류가 발생합니다.
Integer[] numbers = {1, 4, 2, 1}; Object[] objects = numbers; Objects[2] = "B"; //런타임오류: ArrayStoreException
numbers를 Object[]로 캐스팅해도 내부에서는 여전히 Integer를 사용하고 있습니다.
이런 배열에 String 타입의 값을 할당하면 오류가 발생합니다.
코틀린은 이런 결함을 해결하기 위해 invariant로 만들었습니다.
정리
코틀린의 타입 아규먼트의 관계에 제약을 걸 수 있는 굉장히 강력한 제너릭 기능을 제공합니다.
- 타입 파라미터의 기본적인 variance의 동작은 invariant입니다. 만약 Cup<T>라고 하면, 타입 파라미터 T는 invariant입니다. A가 B의 서브타입이라고 할 때 Cup<A>와 Cup<B>는 아무런 관계를 갖지 않습니다.
- out 한정자는 타입 파라미터를 convariant하게 만듭니다. 만약 Cup<T>라고 하면, A가 B의 서브타입이라고 할 때, Cup<A>는 Cup<B>의 서브타입이 됩니다.
- in 한정자는 out과 반대로 Cup<B>가 Cup<A>의 슈퍼타입이 됩니다.
- 코틀린에서 List와 Set의 타입 파라미터는 covariant(out 한정자)입니다.
- 함수 타입의 파라미터 타입은 contravariant(in 한정자)입니다. 그리고 리턴 타입은 covariant(out 한정자)입니다.
728x90'Kotlin > Effective Kotlin 요약' 카테고리의 다른 글
26장 - 함수 내부의 추상화 레벨을 통일하라 (0) 2023.03.12 25장 - 공통 모듈을 추출해서 여러 플랫폼에서 재사용하라 (0) 2023.03.08 23장 - 타입 파라미터의 섀도잉을 피하라 (0) 2023.03.06 22장 - 일반적인 알고리즘을 구현할 때 제너릭을 사용하라 (0) 2023.03.05 21장 - 일반적인 프로퍼티 패턴은 프로퍼티 위임으로 만들어라 (0) 2023.03.04