ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Kotlin] in out 키워드
    코틀린 공부/코틀린 기초 2024. 5. 27. 14:24

    요즘 다른 사람들이 만든 라이브러리를 공부하면서 제너릭과 같이 사용하는 out, in 키워드를 발견했다.

     

    제너릭을 잘 활용하기 위해서 out, in 개념이 무엇인지 알 필요성이 있을것 같아서 공부를 하기로 했다. 

     

    먼저, in, out 키워드를 공부하면서 3가지 개념이 나온다.

    • Invariance - 불변성
    • Convariance - 공변성
    • Contravariance - 반공변성

    1. 불변성이란?

    • 타입 불변성이란 제너틱 타입을 사용하는 클래스나 인터페이스에서 일치하는 타입만 사용할 수 있다. 즉, 해당 타입의 부모, 자식의 타입은 사용이 불가능하다. 
    • in & out 키워드가 없는 일반적인 제너릭이 이런 타입 불변성을 가진다. 
    open class ParentVariance
    class ChildVariance1 : ParentVariance()
    fun main(){
        val childVariance1:Array<ChildVariance1> = arrayOf(ChildVariance1(), ChildVariance1())
    
        // Type mismatch. Required: Array<ParentVariance>, Found: Array<ChildVariance1>
        val parentVariance:Array<ParentVariance> = childVariance1
    }
    

     

    위에 코드를 보면 ChildVariance1을 상속하는 Array<T>를  부모 클래스인 ParanceVariance Array에 넣어주려고 하면 오류가 발생한다.

     

    즉 일반적인 제너릭 타입은 A가 B를 상속받는다고 해도 Class<A>는 Class<B>를 상속하는 것은 아니라는 것이다. 

     

    Array와 다르게 List로 해본다면 에러가 발생하지 않는다.

    val childVariance2:List<ChildVariance1> = listOf(ChildVariance1(), ChildVariance1())
    val parentVariance:List<ParentVariance> = childVariance2

     

    왜냐하면 List는 out이라는 키워드가 붙어 있기 때문이다. 

     

    Array<T> : 

    public class Array<T>

     

    List<out T> :

    public interface List<out E> : Collection<E> 

     

    out 키워드에서 공변성의 개념이 나온다.

     

    2. 공변성이란?

    불변성은 타입을 제한시키고 컴파일 타임에 에러를 잡아주는 등의 코드 안정성에 도움은 되지만 안정성이 보장된 상황에서도 컴파일 에러를 나오게해 개발자가에게 불편을 준다. 그래서 나온 것이 공변성이다. 

     

    공변성은 불변성과 다르게 A가 B를 상속받는다면 Class<A>는 Class<B> 또한 상속되게 해주는 것이 공변성이다. 

     

    공변성은 out 이라는 키워드와 같이 사용된다. 앞서 보았듯이 List는 공변성으로 인해 자식 클래스의 List<ChildVariance>를 할당 받아도 오류가 걸리지 않았다. 

     

    Array<T>또한 out 키워드를 추가한다면 공변성을 추가할수 있다. 

    val childVariance3:Array<ChildVariance1> = arrayOf(ChildVariance1(), ChildVariance1())
    val parentVariance2:Array<out ParentVariance> = childVariance3

     

    out 키워드로 인해 Array<out ParentVariance>는 자식 클래스의 제너릭인 Array<ChildVaraince1>의 인스턴스를 할당 받을수 있다. 

     

    3 반공변성

    반공변성은 공변성의 반대로 진행된다고 생각하면 된다. 

     

    공변성은 불변성과 다르게 A가 B를 상속받는다면 Class<B>는 Class<A> 상속되게 해주는 것이 반공변성이다. 

    val parentVariance3:Array<ParentVariance> = arrayOf(ParentVariance(), ParentVariance())
    val childVariance4:Array<in ChildVariance1> = parentVariance3

     

    in 키워드를 사용하면 공변성과는 반대로

     

    자식클래스의 제네릭인  Array<in ChildVariance1> 타입을 갖고도

    부모 클래스의 제네릭을 갖은 Array<ParentVariance>를 할당 받을수 있는 것이다. 

     

     

    이런 공변성 반공변성의 개념은 아무래도 다양한 타입을 사용하기 위해서 상속 관계에서 좀더 유연하게 사용하려고 만든 것 같다. 

     

    하지만 어떻게 사용해야할지 아직 감이 안잡히기 때문에 이런 부분들은 다른 오픈소스를 공부해보면서 사용방법을 익혀야 할 것 같다. 

Designed by Tistory.