class Cup<T> : variance 한정자가 없으므로 기본적으로 invariant(불공변성)
- Cup<Int>, Cup<Number>, Cup<Nothing> 은 어떠한 관련성이 없음
- class Cup<out T> : 타입 파라미터를 convariant(공변성)으로 만듦
- A가 B의 서브 타입일 때, Cup<A>가 Cup<B>의 서브타입이라는 의미
- Class Cup<in T> : 타입 파라미터를 contravariant(반변성)으로 만듦
- A가 B의 서브 타입일 때, Cup<A>가 Cup<B>의 슈퍼타입
함수 타입은 파라미터 유형과 리턴 타입에 따라서 서로 어떤 관계를 갖는다.
- (Int) -> Any 타입의 함수는 아래와 같은 함수로도 동작한다.
- (Int) -> Number
- (Number) -> Any
- (Number) -> Number
- (Number) -> Int
- 코틀린 함수 타입의 모든 파라미터 타입은 contravariant, 모든 리턴 타입은 covariant
- 함수 타입을 사용할 때는 자동으로 variance 한정자가 사용됨
Variance 한정자의 안정성
- 자바의 Array는 covariant 속성을 갖기 때문에 문제가 발생할 수 있음
Integer[] numbers = {1,2,3,4};
Object[] objects = numbers;
ojects[2] = "B" //ArrayStoreException 발생
- 따라서 코틀린은 Array를 invariant로 만들었음
- 코틀린은 public in 한정자 위치에 covariant 타입 파리미터(out 한정자)가 오는 것을 금지한다.
- 만약 in 한정자 위치 (ex 타입 파라미터)에 있다면, covariant와 업캐스팅을 연결해서, 원하는 타입을 아무것이나 전달할 수 있을 것이기 때문
- 코틀린은 public out 한정자 위치(함수 리턴 타입, 프로퍼티 타입) 에 contravariant 타입 파라미터 (in 한정자)가 오는 것을 금지한다.
- public out 위치는 암묵적으로 업캐스팅을 허용, 하지만 이는 contravariant(in 한정자) 에 맞는 동작이 아님
- Box안에 어떤 타입이 들어 있는지 확실하게 알 수 없기때문
- 만약 프로퍼티를 var 로 선언하면 해당 프로퍼티의 타입은 invariant 인 것으로 보인다.
Variance 한정자의 위치는 크게 두 위치에서 사용할 수 있다.
- 선언 부분
- 클래스와 인터페이스 선언에 한정자가 적용
- 클래스와 인터페이스가 사용되는 모든 곳에 영향
- 클래스와 인터페이스를 활용하는 위치
- 특정한 변수에만 variance 한정자가 적용
- 특정 인스턴스에만 적용해야 할 때 이런 코드를 사용
interface Dog
interface Cutie
data class Puppy(val name: String): Dog, Cutie
data class Hound(val name: String): Dog
data class Cat(val name: String): Cutie
fun main() {
val dogs = mutableListOf<Dog>(Hound("pluto"))
fillWithPuppies(dogs)
println(dogs)
val animals = mutableListOf<Cutie>(Cat("felix"))
fillWithPuppies(animals)
println(animals)
}
fun fillWithPuppies(list: MutableList<in Puppy>) {
list.add(Puppy("jim"))
list.add(Puppy("amy"))
}
- Variance 한정자를 사용하면 위치가 제한될 수 있다.
- MutableList<out T> 가 있다면, get으로 요소를 추출했을 때 T 타입이 나올 것이지만, set은 Nothing 타입의 아규먼트가 전달될 거라 예상되므로 사용불가능하다.
- 모든 타입의 서브타입을 가진 리스트(Nothing 리스트) 가 존재할 가능성이 있기 때문
- MutalbeList<in T> 가 있다면, get set을 모두 사용할 수 있지만, 전달되는 자료형은 Any?가 된다
- 모든 타입의 슈퍼타입을 가진 리스트 (Any 리스트)가 존재할 가능성이 있기 때문
- MutableList<out T> 가 있다면, get으로 요소를 추출했을 때 T 타입이 나올 것이지만, set은 Nothing 타입의 아규먼트가 전달될 거라 예상되므로 사용불가능하다.
'Reading Record > 이펙티브 코틀린' 카테고리의 다른 글
[이펙티브 코틀린] Item 26. 함수 내부의 추상화 레벨을 통일하라 (0) | 2022.05.29 |
---|---|
[이펙티브 코틀린] Item25. 공통 모듈을 추출해서 여러 플랫폼에서 재사용하라 (0) | 2022.05.02 |
[이펙티브 코틀린] Item23. 타입 파라미터의 섀도잉을 피하라 (0) | 2022.05.01 |
[이펙티브 코틀린] Item22. 일반적인 알고리즘을 구현할 때 제네릭을 사용하라 (0) | 2022.05.01 |
[이펙티브 코틀린] Item21. 일반적인 프로퍼티 패턴은 프로퍼티 위임으로 만들어라 (0) | 2022.05.01 |