ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Kotlin] Generic 제네릭이란?, variance : in, out
    Kotlin 2023. 6. 8. 01:15
    반응형

    제네릭이란?

    <> 이렇게 생긴 코드를 많이 봤을 것이다. 이게 바로 제네릭이다.

    제네릭을 사용하면 타입 파라미터 (type parameter)를 받는 타입을 정의할 수 있다.

     

    예를 들어, List라는 타입이 있다면 그 안에 들어가는 원소의 타입을 정의한다.

    val members: List<String> = listOf("A","B","C")

    >>  members 는 문자열을 담은 리스트다. ( 그냥 리스트가 아니라 )

     

    Map 클래스는 key 타입과 value 타입을 타입 파라미터로 받으므로 Map<K,V>가 된다. 이런 제네릭 클래스에 Map<String, Person> 처럼 구체적인 타입을 타입 파라미터로 넘기면 타입을 인스턴스화할 수 있다.

     

    Java와 다르게 Kotlin에서는 제네릭 타입의 타입 인자를 프로그래머가 명시하거나 컴파일러가 추론할 수 있어야 한다.

     

    Variance : in, out

    Invariant (불공변성)

    // Java
    List<String> strs = new ArrayList<String>();
    List<Object> objs = strs; // !!! A compile-time error here saves us from a runtime exception later.
    objs.add(1); // Put an Integer into a list of Strings
    String s = strs.get(0); // !!! ClassCastException: Cannot cast Integer to String

    위의 코드의 경우 2번째 줄에서 컴파일 에러가 난다. 이유는 List<String>은 List<Object>의 sub type이 아니기 때문이다.

    하지만 subtype이라고 하더라도 4번째 줄에서 런타임에러가 발생한다. String이 아닌 Object가 반환되기 때문이이다.

     

    이펙티브 코틀린 item 24: 제네릭 타입과 variance 한정자를 활용하라

    다음과 같은 제네릭 클래스가 있다고 해보자

    class Cup<T>

    타입 파라미터 T는 variance 한정자(out 또는 In) 이 없으므로 기본적으로 invariant 이다.

    invariant 라는 것은 제네릭 타입으로 만들어지는 타입들이 서로 관련성이 없다는 것이다.

    예를 들어 Cup<Int> 와 Cup<Number>, Cup<Any> 는 서로 어떠한 관련도 없다.

     

    하지만 어떤 관련성을 원한다면, out 또는 in 이라는 variance 한정자를 붙여야한다.

     

    Out : 타입 파라미터를 Convariant(공변성) 으로 만든다.

    class Cup<out T>
    open class Dog
    class Puppy: Dog()
    
    fun main(args: Array<String>){
    	val b: Cup<Dog> = Cup<Puppy>() // OK
    	val a: Cup<Puppy> = Cup<Dog>() // 오류 
    }

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

     

    In : 타입 파라미터를 contravariant(반변성) 으로 만든다.

    class Cup<in T>
    open class Dog
    class Puppy: Dog()
    
    
    fun main(args: Array<String>){
        val b: Cup<Dog> = Cup<Puppy>() // 오류
        val a: Cup<Puppy> = Cup<Dog>() // OK
    }

    A가 B의 subtype일 때, Cup<A>가 Cup<B>의 슈퍼타입이라는 의미이다.

     

     

     

     

     

    참고)

    https://kotlinlang.org/docs/generics.html

     

    Generics: in, out, where | Kotlin

     

    kotlinlang.org

     

    반응형

    'Kotlin' 카테고리의 다른 글

    [Kotlin] Scope Function : apply, run, with, also, let 정리  (0) 2023.05.28
Designed by Tistory.