💌 제네릭
📌 제네릭의 이해
💜 제네릭이란?
inline fun <reified T> arrayOf(vararg elements: T): Array<T>
// 제네릭 선언
class MyClass<T>{
var info: T? = null
}
// T말고도 가능
class MyClass<AA>{
var info: AA? = null
}
📌 제네릭 제약
💜 타입 제약
class MyClass<T: Number>{
}
// 인터페이스 여러개 제약
class MyClass<T> where T: MyInterface1, T: MyInterface2{
}
💜 Null 불허 제약
// 기본
class Myclass<T> -> class Myclass<T: Any?> 와 같음
// 불허
class Myclass<T: Any>
📌 Variance
💜 Variance란?
- 하위 클래스로 명시한 타입을 상위 클래스 타입에 대입하기위한 특별한 처리
💜 convariance (사용 측) // 클래스가 사용되는 모든 곳에 적용
- out
하위 제네릭 타입을 상위 제네릭 타입에 대입 가능
상위 제네릭 타입을 하위 제네릭 타입에 대입 불가능
함수의 반환 타입으로 선언 가능
함수의 매개변수 타입으로 선언 불가능
val 프로퍼티에 선언 가능
var 프로퍼티에 선언 불가능
class MyClass<out T>
💜 contravariance (사용 측)
- in
상위 제네릭 타입을 하위 제네릭 타입에 대입 가능
하위 제네릭 타입을 상위 제네릭 타입에 대입 불가능
함수의 반환 타입으로 선언 불가능
함수의 매개변수 타입으로 선언 가능
val/var 프로퍼티에 선언 불가능
📌 타입 프로젝션
💜 이용 측 Variance
- invariance로 선언한 클래스를 이용하는 곳에서 in/out으로 variance가 가능
class MyClass<T>(val data: T){
}
fun some1(arg: MyClass<in Int>){ // 선언된 곳에서만 적용
}
fun some2(arg: MyClass<out Any?>){ // 제네릭 타입 매개변수가 선언된 함수는 이용 불가
array.add(10) ----> 에러
}
💜 스타(*) 프로젝션
fun some3(arg: MyClass<*>){ // 제네릭 타입 매개변수가 선언된 함수는 이용 불가
array.add(10) ----> 에러
}
📌 실행 시점의 제네릭
💜 제네릭과 as, is 이용
- 제네릭 정보는 컴파일위한 자료라 컴파일 후 사라짐
fun some2(arg: List<*>){
if(arg is List<Int>){ //----> 컴파일 시 <*>타입이 <Int>타입인지 몰라서 에러
}
}
fun some3(arg: List<*>){
val intList = args as List<Int> // 형 변환은 되는데
println(intList.sum()) //----> 변환된 데이터 이용 시 에러
}
fun main(args: Array<String>){
some3(listOf(10,20))
some3(listOf("hello","lee"))
}
💜 인라인 함수와 reified
- 제네릭 타입이 실행 시점까지 유지
- inline 함수에서만 사용 가능
📌 Unit, Nothing 타입
💜 Unit 타입
💜 Nothing 타입