본문 바로가기
👨‍💻 프로그래밍/Java, Kotlin, Spring

Kotlin의 inline 함수 알아보기

by 개발자 진개미 2023. 10. 9.
반응형

inline이 뭐하는 걸까?

우리가 코딩을 할 때 적극적으로 의식하지는 않지만, 함수를 호출하는건 어느정도 Overhead를 동반합니다. 보통은 현대 컴퓨터 성능이 워낙 좋고, 컴파일러가 최적화를 최대한 해 줘서 굳이 의식할 필요는 없습니다.

하지만 Kotlin에서는 함수가 일등시민이기 때문에, Parameter에 함수를 Argument로 넘기거나, 함수를 Return Type으로 가지는 함수가 있을 수 있습니다. 이는 자바에서는 FunctionN 객체를 만들거나 Closure를 사용할 경우 함수를 호출하는 방식으로 처리합니다. 이 경우 Kotlin에서 함수형 스타일의 코드가 성능에 어느정도 영향을 줄 수 있겠죠?

그럴때 inline을 쓰면 함수 호출 부분을 없애고 코드안에 함수 내용을 넣어 줍니다.

 

Inline functions | Kotlin

 

kotlinlang.org


inline 될 경우 예시

이 Kotlin 코드는

inline fun add(num1: Int, num2: Int): Int {
    return num1 + num2
}

fun main() {
    val num1 = 1
    val num2 = 1
    val result = add(num1, num2)
 }

이 Java 코드로 컴파일 됩니다.

public static final void main() {
    int num1 = 1;
    int num2 = 1;
    int var = num1 + num2;
}

 

분명 함수를 호출했는데 inline 때문에 함수 호출 부분이 사라지고 라인 안으로 (inline) 된걸 볼 수 있습니다!


inline 함수의 parameter로 자동으로 inline된다

inline 함수는 (가능할 경우) 모든 parameter의 함수도 inline 시킵니다. 그래서 

이 코드는

inline fun repeat(times: Int, exec: () -> Unit) {
    for (i in 1 .. times) {
    	exec()
    }
}

fun main() {
    repeat(1) { println("Hello World") }
}

 

아래와 같이 exec도 inline 됩니다

public static final void main() {
    int i$iv = 1;
    
    while (true) {
        System.out.println("Hello World");
        if (i$iv == 2) { return; }
        ++i$iv;
    }
}

noinline으로 inline 시키고 싶지 않은 parameter 지정하기

하지만 parameter는 inline 시키고 싶지 않을 수 있겠죠? 그런 경우에는 noinline을 써서 이 Parameter는 inline하지 말라고 알려줄 수 있습니다.

inline fun repeat(times: Int, noinline exec: () -> Unit) {
    for (i in 1 .. times) {
    	exec()
    }
}

inline되면 non-local return을 사용할 수 있다!

원래 Lambdafun keyword를 안 써서 return을 사용할 수 없습니다.

return의 역할 자체가 가장 가까운 fun keyword 함수에 return 값을 전해주는 것이기 때문입니다. 하지만 inline을 쓰면 함수가 없어지기 때문에 non-local return을 사용할 수 있습니다!


corssinline으로 non-local return 사용할 수 없게 하기

하지만 Lambda에서 non-local return을 사용하면 예상밖으로 inline 함수를 종료 시키는게 아니라, inline 함수를 호출한 함수를 종료시킵니다. 그래서 inline 함수라 하더라도 오류 방지나 헷갈려서 non-local return을 허용하고 싶지 않을 수 있습니다. 그럴 때는 crossinline을 사용하면 non-local return을 방지할 수 있습니다.

inline fun iterate(numbers: List<Int, crossinline exec: (Int) -> Unit) {}

반응형