[Kotlin] Inline class

 πŸ’‘ κ²½λŸ‰ 클래슀의 ν•œ ν˜•νƒœμΈ inline class에 λŒ€ν•˜μ—¬ ν•™μŠ΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

Inline class

  • Inline classλŠ” κ²½λŸ‰ 클래슀의 ν•œ ν˜•νƒœλ‘œ, 단일 ν”„λ‘œνΌν‹°λ₯Ό 가지고 있으며 λŸ°νƒ€μž„ μ‹œμ— μ‹€μ œ 클래슀 μΈμŠ€ν„΄μŠ€λ‘œ ν• λ‹Ήλ˜μ§€ μ•ŠλŠ” νŠΉμ§•μ΄ μžˆμŠ΅λ‹ˆλ‹€.
  • λŒ€μ‹ μ— ν•΄λ‹Ή 클래슀의 단일 ν”„λ‘œνΌν‹°κ°€ 직접 μΈλΌμΈλ©λ‹ˆλ‹€.
  • μ΄λŠ” μ„±λŠ₯ ν–₯상과 λΆˆν•„μš”ν•œ 객체 생성을 방지할 수 μžˆμŠ΅λ‹ˆλ‹€.

νŠΉμ§•

  • [단일 ν”„λ‘œνΌν‹°] Inline classλŠ” λ°˜λ“œμ‹œ 단일 ν”„λ‘œνΌν‹°λ₯Ό κ°€μ§‘λ‹ˆλ‹€.
  • [κ²½λŸ‰μ„±] λŸ°νƒ€μž„ μ‹œ 객체둜 ν• λ‹Ήλ˜μ§€ μ•Šκ³  단일 ν”„λ‘œνΌν‹° 값이 직접 μ‚¬μš©λ©λ‹ˆλ‹€.
  • [νƒ€μž… μ•ˆμ „μ„±] μΈλΌμΈ 클래슀λ₯Ό ν™œμš©ν•˜λ©΄ μ½”λ“œμ— 더 λͺ…ν™•ν•œ νƒ€μž…μ„ λͺ…μ‹œν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • [ν•¨μˆ˜μ™€ μ—°μ‚°μž μ˜€λ²„λ‘œλ”©] λ©”μ„œλ“œμ™€ μ—°μ‚°μžλ₯Ό μ˜€λ²„λ‘œλ”© ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • [μ œν•œμ‚¬ν•­] μ•„λž˜μ™€ 같은 μ œν•œ 사항을 κ°€μ§‘λ‹ˆλ‹€.
    • init 블둝을 κ°€μ§ˆ 수 μ—†μŒ
    • Anyλ₯Ό 상속할 수 μ—†μœΌλ©°, Nullable νƒ€μž…μ΄ λΆˆκ°€λŠ₯

High-Order Function?

  • μ½”ν‹€λ¦°μ—μ„œλŠ” κ³ μ°¨ν•¨μˆ˜λ₯Ό ν™œμš©ν•΄μ„œ ν•¨μˆ˜λ₯Ό 호좜 인자둜 μ „λ‹¬ν•˜κ±°λ‚˜, λ°˜ν™˜κ°’μœΌλ‘œ ν™œμš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • ν•˜μ§€λ§Œ ν•΄λ‹Ή 방식은 뢀가적인 λ©”λͺ¨λ¦¬ ν• λ‹ΉμœΌλ‘œ 인해 λ©”λͺ¨λ¦¬ 효율이 λ‚˜λΉ μ§€κ³ , ν•¨μˆ˜ 호좜둜 μΈν•œ λŸ°νƒ€μž„ μ˜€λ²„ν—€λ“œκ°€ λ°œμƒν•©λ‹ˆλ‹€.
fun load(data: Int, loadData : () -> Unit) : Int {
		loadData()
		return data
}

fun main() {
		val result = load(10) {
				print("load data")
		}
		print(result)
}
  • μœ„μ™€ 같은 κ³ μ°¨ ν•¨μˆ˜λ₯Ό ν™œμš©ν•œ μ½”λ“œκ°€ μžˆλ‹€κ³  κ°€μ •ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.
  • ν•΄λ‹Ή μ½”λ“œκ°€ 컴파일 μ‹œ μ–΄λ–€ Javaμ½”λ“œλ‘œ λ³€ν™˜λ˜λŠ” 지 ν™•μΈν•˜κΈ° μœ„ν•΄μ„œ Decompileν•˜μ—¬ ν™•μΈν•˜μ˜€μŠ΅λ‹ˆλ‹€.
public final class MainKt {
    public static final int load(int data, Function0<Unit> loadData) {
        loadData.invoke();
        return data;
    }

    public static final void main() {
        int result = load(10, new Function0<Unit>() {
            @Override
            public Unit invoke() {
                System.out.print("load data");
                return Unit.INSTANCE;
            }
        });
        System.out.print(result);
    }
}
  • loadData μ— λžŒλ‹€μ‹μ„ 전달해주도둝 κ΅¬ν˜„ν•œ λΆ€λΆ„μ—μ„œ μƒˆλ‘œμš΄ 객체λ₯Ό μƒμ„±ν•΄μ„œ λ„˜κ²¨μ£ΌλŠ” μ‹μœΌλ‘œ λ³€ν™˜λ˜λŠ” 것을 확인할 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.
  • λ˜ν•œ λ„˜κΈ΄ 객체λ₯Ό 톡해 ν•¨μˆ˜ ν˜ΈμΆœμ„ κ΅¬ν˜„ν•˜λ„λ‘ λ˜μ–΄μžˆλŠ”λ°, μ΄λŸ¬ν•œ 방식은 λ¬΄μ˜λ―Έν•œ 객체λ₯Ό μƒμ„±ν•˜μ—¬ λ©”λͺ¨λ¦¬λ₯Ό μ°¨μ§€ν•˜κ³  λ‚΄λΆ€μ μœΌλ‘œ μ—°μ‡„적인 ν•¨μˆ˜ ν˜ΈμΆœμ„ ν•˜κ²Œ 될 κ°€λŠ₯성이 μžˆμŠ΅λ‹ˆλ‹€.
  • μ΄λŠ” μ˜€λ²„ν—€λ“œλ₯Ό λ°œμƒμ‹œμΌœ μ„±λŠ₯을 λ–¨μ–΄λœ¨λ¦΄ μœ„ν—˜μ΄ μ‘΄μž¬ν•©λ‹ˆλ‹€.
  • λ”°λΌμ„œ μ΄λŸ¬ν•œ λžŒλ‹€μ‹ λ‚΄λΆ€μ˜ μ½”λ“œλ“€μ„ 컴파일 μ‹œ λžŒλ‹€λ₯Ό ν˜ΈμΆœν•˜λŠ” 뢀뢄에 μ£Όμž…ν•˜λŠ” 방식을 ν™œμš©ν•  수 μžˆλŠ”λ°, 이에 Inline Function을 μ μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

인라인 ν•¨μˆ˜ ν™œμš©

inline class UserId(val id: String)

fun getUser(userId: UserId) {
    println("User ID: ${userId.id}")
}

fun main() {
    val userId = UserId("12345")
    getUser(userId) 
}
  • UserIdλŠ” 인라인 클래슀이며, id:Strint μ΄λΌλŠ” 단일 ν”„λ‘œνΌν‹°λ₯Ό κ°€μ§‘λ‹ˆλ‹€.
  • 이 λ•Œ UserIdλŠ” λŸ°νƒ€μž„ μ‹œ 객체둜 μ‘΄μž¬ν•˜μ§€ μ•Šκ³  단일 ν”„λ‘œνΌν‹° 값이 직접 μ‚¬μš©λ˜λ©°, μ•„λž˜μ™€ 같은 이점을 얻을 수 μžˆμŠ΅λ‹ˆλ‹€.
    • [μ„±λŠ₯] κ°μ²΄ 생성 μ˜€λ²„ν—€λ“œκ°€ μ—†μ–΄ μ„±λŠ₯이 ν–₯μƒλ©λ‹ˆλ‹€.
    • [λͺ…ν™•ν•œ νƒ€μž…] μ½”λ“œμ˜ νƒ€μž… μ•ˆμ „μ„±κ³Ό 가독성을 λ†’μ—¬μ€λ‹ˆλ‹€.
    • [λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰ κ°μ†Œ] λΆˆν•„μš”ν•œ 객체 생성이 쀄어듀어 λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰μ΄ κ°μ†Œν•©λ‹ˆλ‹€.

Nullable 인라인 클래슀

  • Kotlin 1.5λΆ€ν„° @JvmInline μ–΄λ…Έν…Œμ΄μ…˜μ„ ν™œμš©ν•˜μ—¬ nullable 인라인 클래슀λ₯Ό μ •μ˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
@JvmInline
value class UserId(val id: String)

fun getUser(userId: UserId?) {
    if (userId != null) {
        println("User ID: ${userId.id}")
    } else {
        println("User ID is null")
    }
}

κ³ μ°¨ν•¨μˆ˜μ™€ 인라인 클래슀

  • μœ„μ—μ„œ μž‘μ„±ν•œ load() κ³ μ°¨ ν•¨μˆ˜λ₯Ό 인라인 클래슀둜 μ„ μ–Έν–ˆμ„ λ•Œ, μ–΄λ–€ 차이가 μžˆλŠ”μ§€ ν™•μΈν•΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€.
public final class MainKt {
    public static final void main() {
        System.out.print("load data");
        int result = 10;
        System.out.print(result);
    }
}
  • inline ν‚€μ›Œλ“œλ₯Ό μ»΄νŒŒμΌν•˜μ—¬ μžλ°” μ½”λ“œλ‘œ λ³€ν™˜ν•œλ‹€λ©΄, load ν•¨μˆ˜κ°€ 직접 ν˜ΈμΆœλ˜μ§€ μ•Šκ³  load ν•¨μˆ˜μ˜ 본문이 main ν•¨μˆ˜μ— 직접 μ‚½μž…λ˜μ–΄ ν•¨μˆ˜ ν˜ΈμΆœμ— λŒ€ν•œ μ˜€λ²„ν—€λ“œλ₯Ό 쀄일 수 μžˆμŠ΅λ‹ˆλ‹€.
  • 이런 경우 κ³ μ°¨ ν•¨μˆ˜κ°€ λΉˆλ²ˆν•˜κ²Œ ν˜ΈμΆœλ˜λŠ” κ²½μš°μ— μ΅œμ ν™”λ₯Ό 진행할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ»΄νŒŒμΌλ˜λŠ” λ°”μ΄νŠΈμ½”λ“œμ˜ 양은 μ¦κ°€ν•˜μ—¬λ„, κ°μ²΄λ₯Ό μƒμ„±ν•˜κ±°λ‚˜ ν•¨μˆ˜λ₯Ό 또 ν˜ΈμΆœν•˜λŠ” λ“±μ˜ λΉ„νš¨μœ¨μ μΈ 행동은 ν•˜μ§€ μ•Šκ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

noinline Keyword

  • 인라인 ν•¨μˆ˜λŠ” 일반 ν•¨μˆ˜λ³΄λ‹€ μ„±λŠ₯이 μ’‹μ§€λ§Œ, λ‚΄λΆ€μ μœΌλ‘œ μ½”λ“œλ₯Ό λ³΅μ‚¬ν•˜λŠ” κ°œλ…μ΄κΈ° λ•Œλ¬Έμ— 인자둜 전달받은 ν•¨μˆ˜λŠ” λ‹€λ₯Έ ν•¨μˆ˜λ‘œ μ „λ‹¬λ˜κ±°λ‚˜ 참쑰될 수 μ—†μŠ΅λ‹ˆλ‹€.
  • μ•„λž˜μ˜ 예λ₯Ό λ³΄κ² μŠ΅λ‹ˆλ‹€.
inline fun load(data: Int, loadData : () -> Unit, loadData2: () -> Unit) : Int {
		loadData()
		return data
}

fun load2(data: Int, loadData2 : () -> Unit) : Int {
		loadData2()
		return data
}

fun main() {
		load(1, {
				print("load Function")
		}, {
				print("load2 Function")
		})
}
  • μœ„μ—μ„œλŠ” 전달받은 ν•¨μˆ˜μ˜ 일뢀λ₯Ό λ‹€λ₯Έ ν•¨μˆ˜λ‘œ λ„˜κ²¨μ£Όκ³  μžˆμŠ΅λ‹ˆλ‹€.
  • μ΄λŠ” μ»΄νŒŒμΌ μ—λŸ¬λ₯Ό λ°œμƒν•˜κ²Œ 되며, μ΄λ•Œ ν•„μš”ν•œ 것이 noninline ν‚€μ›Œλ“œμ˜ ν™œμš©μž…λ‹ˆλ‹€.
inline fun load(data: Int, loadData : () -> Unit, noinline loadData2: () -> Unit) : Int {
		loadData()
		return data
}
  • inlineμ—μ„œ μ œμ™Έμ‹œν‚¬ 인자 μ•žμ— noinline ν‚€μ›Œλ“œλ₯Ό λΆ™μ΄λ©΄μ„œ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

κ²°λ‘ 

  • inline은 일반 ν•¨μˆ˜λ³΄λ‹€ 쒋은 μ„±λŠ₯을 가지며, κ³ μ°¨ν•¨μˆ˜μ—μ„œ λ°œμƒν•˜λŠ” μ˜€λ²„ν—€λ“œλ₯Ό 쀄일 수 μžˆλ‹€λŠ” μž₯점을 가지고 μžˆμŠ΅λ‹ˆλ‹€.
  • ν•˜μ§€λ§Œ μ§€λ‚˜μΉœ inline ν•¨μˆ˜μ˜ ν™œμš©μ€ λ°”μ΄νŠΈμ½”λ“œ 양을 μ¦κ°€μ‹œν‚€λ©° μ΄λŠ” μ„±λŠ₯ μ•…ν™”λ‘œ μ΄μ–΄μ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • inline μ²˜λ¦¬λŠ” 1~3μ€„μ˜ 길이λ₯Ό ꢌμž₯ν•˜κ³  있으며, μ μ ˆν•˜κ²Œ ν™œμš©ν•œλ‹€λ©΄ 맀우 쒋은 μ„±λŠ₯을 얻을 수 μžˆμŠ΅λ‹ˆλ‹€.

μ°Έκ³ 

https://kotlinlang.org/docs/inline-classes.html

https://medium.com/android-news/learning-kotlin-inline-functions-18a94d3efe46