Android Development with Kotlin - Generics Are Your Friends |
이 정리글은 Kotlin in Action 책을 보고 실무에 Kotlin 을 사용하던 사람이 몰랐던 내용이나 remind 하고 싶은 내용을 위주로 정리한 글입니다.
제대로 내용을 파악하시려면 책을 구매해서 읽어보세욤~
-
Kotlin 에서 generics 는 기본적으로는 invariant 이다.
invariant 는 subtyping relation 이 없다는 것
-
generic 에서 subtyping 관계가 유지되는 것을 co-variant 라고 하고,
반대로 유지되는 것을 contra-variant.
그리고 유지되지 않는 것을 invariant 라고 한다.
-
Java 의 upper bound wildcard 설정은 co-variant 를 만들어주는데, 이를 Kotlin 에서는 out 으로 한다.
Java 의 lower bound wildcard 설정은 contra-variant 를 만들어주는데, 이를 Kotlin 에서는 in 으로 한다.
-
Use-site variance vs. declaration-site variance.
아래는 use-site variance 의 예
interface BaseView interface ProductView: BaseView class Presenter<T> var presenter: Presenter<out BaseView> = Presenter<BaseView>() var productPresenter = Presenter<ProductView>() presenter = productPresenter
아래는 declaration-site variance 의 예
interface BaseView interface ProductView: BaseView class Presenter<out T> var presenter = Presenter<BaseView>() var productPresenter = Presenter<ProductView>() presenter = productPresenter
-
Java 에서 array 는 co-variant 하다.
그래서 Object[] 를 요구하는 곳에 String[] 을 전달할 수 있다.
그러나 Kotlin 에서 array 는 invariant 하다.
Array<Any> 를 요구하는 곳에 Array<String> 을 전달할 수 없다.
-
Kotlin 에서의 List 는 immutable 하기 때문에 co-variant 이다.
MutableList 는 invariant 하다.
-
invariant 일 경우에는 generic 이 in(param), out(return) 어디든 쓰일 수 있다.
co-variant 일 경우네는 generic 이 out(return) 에만 쓰일 수 있고, contra-variant 일 경우에는 in(param) 에만 쓰일 수 있다.
그리고 이 position restriction 은 private 인 경우에는 적용되지 않는다.
-
constructor 의 param 의 경우는 항상 invariant 로 사용된다.
즉, in, out position 에 상관 없다는 이야기이다.
이렇게 한 이유는 constructor 는 생성시 한번만 불리고 그 이후로는 불리지 않음이 guarantee 되기 때문이다.
단, variance modifier 를 넣었을 때 public 이면 val 만 가능하고, private 이면 var 도 가능하다.
-
generic type erase 때문에 같은 JVM signature overload 가 불가능하다
fun sum(ints: List<Int>){ ... } fun sum(ints: List<Long>){ ... } // compile error
위의 코드를 수정하려면...
위쪽의 @JvmName(“intSum”) 과 같이 annotation 을 붙여주면 된다.
Kotlin 에서는 동일하게 그냥 sum 으로 부를 수 있지만, Java 에서 호출할대는 intSum 으로 호출해야 한다...
-
Reified type parameter
fun <T> typeCheck(s: Any){ if(s is T){ ... }else{ ... } }
위 코드는 compile error 가 난다.
이유는 T 가 erase 되기 때문이다.
이를 방지하기 위해.. 즉 type erase 를 안 되게 하려면 reified 를 넣어줘야 한다.
그리고 reified 는 inline 에서만 작동한다. ( inline 에서만 작동하는 이유는 실제 inline 되면서. T 를 실제 class 로 치환하기 때문, JVM 의 기본특성인 type erasure 자체를 거스를 순 없다. )
inline fun <reified T> typeCheck(s: Any){ ... }
-
다음과 같이 reified type 에 대해 reflection 도 사용할 수 있다.
inline fun <reified T> isOpen(): Boolean { return T::class.isOpen }
-
Kotlin 에서는 raw type collection 을 정의할 수 없다.
SimpleList<> // compile error SimpleList<*> // ok, called star-projection
-
val anyBox: Box<Any> = Box<Int> // Error: Type mismatch val anyBox: Box<*> = Box<Int> // ok.
-
Generic type parameter convention.
E : Element
K : Key
N : Number
T : Type
V : Value
S, U, V, and so on
T, R : Type, Return Type
댓글