[Kotlin] inline 키워드란? with crossinline

박상군·2024년 11월 7일
0

Kotlin

목록 보기
8/9
post-thumbnail

인라인 한번도 안 타본 1인

inline 키워드는 함수 호출을 인라이닝(inlining) 하도록 컴파일러에 지시하는 키워드로, 주로 람다나 고차 함수에서 성능을 최적화할 때 사용된다.

inline 키워드

  1. 함수 호출 비용 감소
    inline 키워드가 붙은 함수는 컴파일 시 함수 호출이 인라인되어 함수의 본문이 호출 지점에 직접 삽입된다. 따라서 함수 호출에 따른 오버헤드를 줄일 수 있다.

  2. 람다와 고차 함수에서 유용함
    람다 표현식은 객체로 만들어지고, 메모리에 할당되며 함수 호출 시 람다 객체를 통해 호출이 이루어진다.
    inline 키워드를 사용하면 람다도 인라인으로 삽입되어 불필요한 객체 생성이 줄어들고 성능이 향상된다.
    따라서 고차 함수에 람다를 여러 개 넘기는 경우, inline을 사용해 성능 최적화를 할 수 있다.

  3. Non-local returns
    인라인 함수 내에서 람다를 사용할 때 return을 통해 호출한 지점에서 함수 전체를 종료할 수 있다. 일반적인 람다에서는 return이 로컬 리턴(local return)으로 작동하지만, inline 함수의 경우 함수 자체를 종료하는 non-local return이 가능하다.

inline fun inlineFunction(value: Int, block: (Int) -> Int): Int {
    return block(value)
}

fun main() {
    val result = inlineFunction(5) { it * it }
    println(result) // 출력: 25
}

inline 함수에 전달되는 람다 중 특정 람다만 인라인하고 싶지 않은 경우, noinline 키워드를 사용할 수 있다.

inline fun performOperation(value: Int, block1: (Int) -> Int, noinline block2: (Int) -> Int): Int {
    return block2(block1(value))
}

위처럼 noinline 키워드를 사용하면 block2 람다는 인라인되지 않는다.

inline 사용 시 주의할 점으로는

  • 코드 크기 증가: 인라인 함수는 호출 위치에 본문이 복사되므로, 함수가 많거나 복잡하면 바이너리 크기가 커질 수 있다.
  • 재귀 함수: 인라인 함수는 자기 자신을 재귀적으로 호출할 수 없다.

crossinline 키워드

crossinline 키워드는 inline 함수의 파라미터로 전달된 람다가 비지역(non-local) return을 허용하지 않도록 할 때 사용된다.

일반적으로 inline 함수의 람다에서는 비지역 return을 사용할 수 있다.
비지역 return은 람다 내부에서 return을 호출하면, 해당 람다뿐 아니라 inline 함수를 호출한 곳에서 바로 리턴되도록 하는 것이다. 그러나 때로는 비지역 return을 허용하면 문제를 일으킬 수 있는 경우가 있어서, 이를 방지하기 위해 crossinline을 사용한다.

inline fun nocrossinlineFunction(block: () -> Unit) {
    println("Before block")
    block() // 이곳에서 람다 호출
    println("After block")
}

fun main() {
    myFunction {
        println("Inside block")
        return // 비지역 return이므로 main 함수로 리턴
    }
    println("Outside block") // 호출되지 않는다.
}
inline fun crossinlineFunction(crossinline block: () -> Unit) {
    println("Before block")
    action() // 비지역 return이 허용되지 않아 에러 발생
    println("After block")
}

fun main() {
    myFunction {
        println("Inside block")
        // return // 컴파일 오류 발생
    }
    println("Outside block")
}

위와 같이 crossinline 사용 시 람다에서 비지역 return을 호출할 수 없게 되어 오류가 발생해 비지역 return을 방지한다.

crossinline은 다음과 같은 경우에 유용합니다.

  • 비동기 처리나 콜백 함수로 람다가 전달될 때: 이런 경우 람다가 다른 스레드나 비동기 작업에 의해 실행될 수 있으므로 비지역 return이 호출되면 예기치 않은 동작을 유발할 수 있다.
  • 제어 흐름을 명확하게 유지하고 싶을 때: inline 함수에서 코드 흐름이 혼란스럽지 않도록 return을 제한하고 싶을 때 crossinline을 사용한다.
    따라서, crossinline을 사용하면 안전한 코드 작성과 더불어, 코드 흐름을 명확하게 제어할 수 있습니다.

잘 사용한다면 성능 최적화 면에서 좋을 것 같다!

0개의 댓글