ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 24장 - 제네릭 타입과 variance 한정자를 활용하라
    Kotlin/Effective Kotlin 요약 2023. 3. 7. 00:01
    728x90

    불공변성(invariant)이란?

    제네릭 타입으로 만들어지는 타입이 서로 관련성이 없다는 의미입니다.

     

    예를 들어 다음 제네릭들은 서로 어떠한 관련성도 갖지 않습니다.

    - Cup<Int>

    - Cup<Number>

    - Cup<Any>

    - Cup<Nothing>

     

    공변성(covariant)이란?

    어떤 관련성을 원할 경우 out 또는 in이라는 variance 한정자를 붙일 수 있습니다.

    out은 타입 파라미터를 공변성으로 만듭니다.

    A가 B의 서브타입일때 Cup<A>가 Cup<B>의 서브타입이라는 의미입니다.

     

    in은 반대 의미입니다.

    타입 파라미터를 contravariant(반변성)으로 만듭니다.

    A가 B의 서브타입일때 Cup<A>가 Cup<B>의 슈퍼타입이라는 의미입니다.

     

    코틀린에서 함수와 variance

    코틀린 함수 타입의 모든 파라미터 타입은 contravariant입니다.

    또한 모든 리턴 타입은 covariant입니다.

     

    (Int) -> Any 타입의 함수는 다음과 같이도 동작합니다.

    (Int) -> Number

    (Number) -> Any

    (Number) -> Number

    (Number) -> Int

     

    variance 한정자의 안정성

    자바의 배열은 convariant입니다.

    이로 인해 컴파일 중에 아무런 문제는 없지만, 런타임 오류가 발생합니다.

    Integer[] numbers = {1, 4, 2, 1};
    Object[] objects = numbers;
    Objects[2] = "B"; //런타임오류: ArrayStoreException

    numbers를 Object[]로 캐스팅해도 내부에서는 여전히 Integer를 사용하고 있습니다.

    이런 배열에 String 타입의 값을 할당하면 오류가 발생합니다.

     

    코틀린은 이런 결함을 해결하기 위해 invariant로 만들었습니다.

     

    정리

    코틀린의 타입 아규먼트의 관계에 제약을 걸 수 있는 굉장히 강력한 제너릭 기능을 제공합니다.

     

    - 타입 파라미터의 기본적인 variance의 동작은 invariant입니다. 만약 Cup<T>라고 하면, 타입 파라미터 T는 invariant입니다. A가 B의 서브타입이라고 할 때 Cup<A>와 Cup<B>는 아무런 관계를 갖지 않습니다.

     

    - out 한정자는 타입 파라미터를 convariant하게 만듭니다. 만약 Cup<T>라고 하면, A가 B의 서브타입이라고 할 때, Cup<A>는 Cup<B>의 서브타입이 됩니다.

     

    - in 한정자는 out과 반대로 Cup<B>가 Cup<A>의 슈퍼타입이 됩니다.

     

    - 코틀린에서 List와 Set의 타입 파라미터는 covariant(out 한정자)입니다.

     

    - 함수 타입의 파라미터 타입은 contravariant(in 한정자)입니다. 그리고 리턴 타입은 covariant(out 한정자)입니다.

     

     

     

    728x90

    댓글

Designed by Tistory.