interface Consumer<in T> {
fun consume(t: T)
}
class WriteOnlyBox<in T>(private var item: T) : Consumer<T> {
override fun consume(t: T) {
}
}
위 같은 코드가 있습니다.
위 코드에서 WriteOnlyBox의 생성자 프로퍼티의 private var item: T
에서 private
만 제거 후 IDE에서 본다면 다음과 같이 나옵니다.
type parameter T is declared as 'in' but occurs in 'invariant' position in type T
이게 무슨말일까요?
위 설명을 이해 하기전에 공변성과 반공변성의 특징 차이를 알아야 합니다.
in
, out
키워드와 타입 파라미터의 관계는 해당 포스팅에서 설명하지 않습니다.
두 변성의 큰 특징은 다음과 같은데요,
위 설명이 조금 헷갈린다면 아래 예제를 봐볼까요?
// 반공변성(Consumer(소비자))
interface Consumer<in T> {
fun consume(item: T)
}
class StringConsumer : Consumer<String> {
override fun consume(item: String) { // 사용자가 데이터를 사용, 소비함.
println("Consumed: $item")
}
}
// 공변성(Producer(생산자))
interface Producer<out T> {
fun produce(): T // 데이터를 제공, 생산
}
class StringProducer : Producer<String> {
override fun produce(): String { // 생산한 데이터를 사용자가 읽음.
return "Produced String"
}
}
즉, 공변성으로 가지는 타입은 값을 생산(get)로만 사용이 가능하고, 반공변성을 가지는 타입은 값을 소비(set)만 가능함.
interface Consumer<in T> {
fun consume(t: T)
}
class WriteOnlyBox<in T>(var item: T) : Consumer<T> {
override fun consume(t: T) {
}
}
그럼 다시 private
이 제거된 코드로 돌아와서, 제네릭 클래스인 WriteOnlyBox
는 반공변성 타입을 가지고 있습니다.
즉, 소비만 가능해야함. 하지만, var
로 설정되어 있어, read/write 둘 다 가능한 상태임.
즉, 외부에선 get하지 못하게 private
으로 설정해야함.
interface Consumer<in T> {
fun consume(t: T)
}
class WriteOnlyBox<in T>(private var item: T) : Consumer<T> {
override fun consume(t: T) {
}
}