ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 6-3. 특별한 클래스 사용하기 : 인라인 클래스(값 클래스)
    Study(종료)/Kotlin 22.09.13 ~ 12.18 2022. 10. 23. 20:55

    6장

    6-1. 특별한 클래스 사용하기 : 이넘(enun) 클래스

    6-2. 특별한 클래스 사용하기 : 데이터 클래스

    6-3. 특별한 클래스 사용하기 : 인라인 클래스(값 클래스)


    6.3. 인라인 클래스(값 클래스)

    프로그램에서 통화(돈)이라는 개념을 처리하고 싶을 때, 서로 다른 통화를 구분없이 섞어서 사용한다면

    실수할 가능성도 많고, 복잡해진다.

    이 경우 여러 통화를 서로 다른 클래스로 정의해 타입 시스템의 도움을 받아 오류를 줄일 수 있는데,

    래퍼 클래스와 유틸리티 함수를 사용하면 이러한 방법을 사용할 수 있다.

    class Dollar(val amount: Int) // amount = 센트
    class Euro(val amount: Int) // amount = 센트
    
    fun Dollar.toEuro() = ..
    fun Euro.toDollar() = ..

    새로운 통화를 만들 때 마다 래퍼 클래스를 생성해야 하므로 래퍼 클래스를 사용하면 런타임 부가 비용이 발생한다.

    위 코드처럼 감싸야 하는 대상이 원시 타입이면 부가 비용 문제가 더 커진다.(런타임에서 실행 시간이 늘어난다)

    이 문제 해결을 위해 코틀린은 인라인 클래스(inline class)를 도입했다.

    원시 타입의 값과 마찬가지로 부가 비용이 없으므로 인라인 클래스를 값 클래스라고 부르기도 한다.

    1) 인라인 클래스 정의하기

    인라인 클래스를 정의하려면 inline class를 클래스 이름 앞에 붙여야 한다.

    inline class Dollar(val amount: Int)
    inline class Euro(val amount: Int)

    인라인 클래스의 주생성자에는 불변 프로퍼티를 하나만 선언해야 한다.

    inline class Dollar(val amount: Int, val x:String) 
    // Error : Inline class must have exactly one primary constructor parameter

    런타임에 클래스 인스턴스는 별도의 래퍼 객체를 생성하지 않고 이 프로퍼티의 값으로 표현된다.

     

    인라인 클래스도 자체 함수와 프로퍼티를 포함할 수 있다.

    inline class Dollar(val amount: Int){
        fun add(d: Dollar) = Dollar(amount + d.amount)
        val isDebt get() = amount < 0
    }
    
    fun main(){
        println(Dollar(15).add(Dollar(20)).amount) // 35
        println(Dollar(100).isDebt) // false
    }

    인라인 클래스도 프로그램 내 nullable-type 변수에 원시값을 대입하는 경우 암시적으로 박싱한다.

    최적화를 위해 컴파일러는 가능하면 박싱하지 않은 값을 사용하려고 하지만,

    박싱하지 않은 값을 사용할 수 없는 경우, 컴파일러는 인라인되지 않는 형태로 클래스를 사용한다.

    인라인 클래스 인스턴스는 다른 어떤 타입의 값으로 캐스팅하지 않고도 정확히 상응하는 (프로퍼티) 타입의

    값으로 사용될 수 있는 경우 인라인 될 수 있다 라는 규칙을 기억하자.

    fun safeAmount(dollar: Dollar?) = dollar?.amount ?: 0
    
    fun main(){
        println(Dollar(15).amount) // inline
        println(Dollar(15)) // Any? type > not inline
        println(safeAmount(Dollar(15))) // Dollar? type > not inline
    }

    2) 부호 없는 정수

    부호 없는 타입을 기반으로 인라인 클래스로 작성된 부호 없는 정수 타입이 있다.부호 없는 정수 타입은 부호 있는 정수 타입의 이름 앞에 U를 붙여 사용할 수 있다.

    	
        val unsignedByte: UByte = 1u // UByte : 0 ~ 255, 1byte
        val uShort: UShort = 100u // UShort : 0 ~ 65535, 2byte
        val uInt: UInt = UInt.MAX_VALUE // UInt : 4294967295(2^32-1), 4byte
        val uLong: ULong = ULong.MAX_VALUE // ULong : 18446744073709551615(2^64-1), 8byte
    
        println(uInt.toInt())
        
    //    println(1u + 2) 
    //    Error : Conversion of signed constants to unsigned ones is prohibited

     


    마치며

    그래도 이번장은 짧기도 하고 내용역시  부담이 많이 없었다.

    사실 원래 스터디날이 기사 시험날이라 기사 공부하고, 그날은 좀 쉬고싶어서 스터디 참가를 못한다고 했는데.

    카카오 서버가 터져버려서 아예 그날 스터디 진행을 못했다.

     

    이번장이 부담이 없는 대신 다음장은 부담이 좀 많이 된다.

    다음장은 컬렉션과 I/O 자세히 알아보기이고, 무려 60쪽이나 된다..

    다 정리할 수 있을지는 모르겠지만, 할수 있는 만큼 최대한 해봐야겠다

     

    반응형

    댓글

Designed by Tistory.