-
[코틀린] 제네릭 in / out개발/Kotlin 2023. 5. 24. 16:47
재사용성을 위한 동일한 코드를 여러타입에 지원해주기 위해 제네릭 타입 선언시 <out T> , <in T>와 같은 접두어를 볼수있다.
무엇을 위해 왜 사용되는지 알아 보려고 한다.불변성(Invariance) - <T>
기본적으로 제네릭은 불변성을 가지고 있다. 제네릭 파라미터로 T를 받는다고 하면 T의 부모 및 자식과 비교해 보면 Type mismatch. 되며 타입이 정확히 일치하여야 한다. 안정성을 고려한 거라 볼 수 있다.
class IPad : Apple() {} class IPhone : Apple() {} open class Apple {}
위와 같은 상속 관계로 알아보면
fun main() { val iPads = arrayOf(IPad(), IPad()) getAppleDevice(iPads) //error -> Type mismatch } fun getAppleDevice(device: Array<Apple>) { println("device size -> ${device.size}") }
getAppleDevice에서 Array<Apple>을 받지만 Array<IPad>을 넘겨주고있다.
부모 자식 관계 이지만 타입이 정확히 일치하지 않아 에러가 발생하게된다.public class Array<T>
Array의 제네릭 구현 형태를 보면 위와 같다.
공변성(Covariance) - <out T>
공변성은 A가 B의 서브타입이면, T<A>는 T<B>의 서브타입으로 볼 수 있다.
안정성을 위해 위와 같은 타입은 제약되어있었지만 out 을 선언하여 허용 해줄 수 있다.
위의 코드에서 Array를 List로 변경 해보면 알수있다.
fun main() { val iPads = listOf(IPad(), IPad()) getAppleDevice(iPads) } fun getAppleDevice(device: List<Apple>) { println("device size -> ${device.size}") } 결과 device size -> 2
public interface List<out E> : Collection<E>
반공변성(contravariance) - <in T>
공변성과 반대되며 A가 B의 서브타입이면, T<B>는 T<A>의 서브타입이다.
open class Apple : Device() {} open class Device {}
Apple의 부모로 Device가 있다면
fun main() { val devices = arrayOf(Device()) getAppleDevice(devices) } fun getAppleDevice(device: Array<in Apple>) { println("device size -> ${device.size}") }
in 을 사용하여 가능하다.
out (Read only) , in(Write only)
out이나 in으로 받은 파라미터를 Read , Write 할 경우에도 차이점이 발생한다.
우선 out의 경우 Read만 가능한데 out Apple 일 때 Apple의 하위 객체가 들어오게 됨으로 추측 가능하여 Read 할 수 있게 된다.
반면 Write의 경우 종속관계가 없는 객체가 들어올 수 있으므로 Write 하지 못하게 된다.in의 경우 반대가 됨으로 상위 객체가 들어와 그 하위 객체를 Write 할 수 있게 된다.
'개발 > Kotlin' 카테고리의 다른 글
[코틀린] 변수 선업하기 (var, val) (0) 2019.03.07