Kotlin Generic 정리
09 Oct 2022패스트 캠퍼스 실무 프로젝트로 배우는 Kotlin & Spring 강의 정리
Generic
- 제네릭을 선언할 때 타입 파라미터(
<T>
)를 사용하여 선언 - 클래스를 생성할 때 생성자의 파라미터에 의해 타입을 추론할 수 있으므로 타입 인자 생략 가능
class Sample<T>(val t: T)
fun main() {
val sample = Sample<String>("sample1")
val sample2 = Sample("sample2")
}
- 변수의 타입에 제네릭을 사용하거나 생성자에서 타입 인자를 추가할 수 있음
fun main() {
val list1: MutableList<String> = mutableListOf()
val list2 = mutableListOf<String>()
}
- Star projections(
<*>
)- 어떤 타입 인자를 받을 지 알 수 없지만, 안전하게 사용하고 싶을 때 사용
fun main() {
val list: List<*> = listOf("a", "b", "c")
val list2: List<*> = listOf(1, 2, 3)
}
-
변성
- 타입 파라미터화 된 타입의 관계를 설명하는 개념
- PECS: Effective Java에서 Producer는 extends, Consumer는 Super를 사용하는 규칙
- 무공변(invariant): 타입 인자들 사이에 하위 타입 관계가 있어도 아무 관계가 없는 타입인 것으로 간주
- 제네릭을 쓸 때 기본적으로 무공변성
- 공변(covariant): 타입 인자의 상하위 타입 관계에 따라 제네릭 타입의 상하윕 타입 관계가 함께 변하는 것
- 자바 제네릭의 extends에 해당, 코틀린에서는
out
- 자바 제네릭의 extends에 해당, 코틀린에서는
class MyGenerics<T>(val t: T) fun main() { val generics = MyGenerics<String>("test") // String은 CharSequence의 서브 타입 // charGenerics에 generics를 할당할 수 있을 것 같지만, 컴파일 에러 발생 val charGenerics : MyGenerics<CharSequence> = generics }
// out 키워드를 사용하여 공변성 부여 class MyGenerics<out T>(val t: T) fun main() { val generics = MyGenerics<String>("test") // 컴파일 에러 발생하지 않음 val charGenerics : MyGenerics<CharSequence> = generics }
- 반변(contravariant)
- 자바 제네릭의 super에 해당, 코틀린에서는
in
- 자바 제네릭의 super에 해당, 코틀린에서는
class Bag<T> { fun saveAll(to: MutableList<T>, from: MutableList<T>) { to.addAll(from) } } fun main() { val bag = Bag<String>() // 컴파일 에러 발생 bag.saveAll(mutableListOf<CharSequence>("1", "2"), mutableListOf<String>("3", "4")) }
// in 키워드 사용하여 반공변성 사용 class Bag<T> { // MutableList<T> 타입이 MutableList<in T> 보다 상위 타입이 됨 fun saveAll(to: MutableList<in T>, from: MutableList<T>) { to.addAll(from) } } fun main() { val bag = Bag<String>() bag.saveAll(mutableListOf<CharSequence>("1", "2"), mutableListOf<String>("3", "4")) }