Kotlin 문법 - inline, crossinline, noinlin

느린달팽이·2025년 10월 15일

코틀린 복습

목록 보기
23/25

inline, noinline, crossinline 세 가지 키워드의 역할과 차이


1️⃣ inline 이란?

“함수 호출을 인라인(복붙) 하여 호출 오버헤드를 줄이는 키워드”

기본 개념

  • 일반 함수는 호출 시 스택에 함수를 넣고 실행하지만, inline 함수는 컴파일 시 함수 본문을 호출 위치에 그대로 삽입합니다.
  • 즉, 함수 호출 비용(call overhead) 을 제거해줍니다.

✅ 예시

inline fun repeatTwice(action: () -> Unit) {
    action()
    action()
}

fun main() {
    repeatTwice { println("Hi") }
}

컴파일 시 내부적으로 이렇게 바뀜 👇

(즉, 함수 호출 자체가 사라집니다.)

fun main() {
    println("Hi")
    println("Hi")
}

효과

  • 성능 최적화 (람다 호출 오버헤드 제거)
  • 비지역 반환(non-local return) 가능 (람다 안에서 return하면 바깥 함수 종료)

2️⃣ noinline 이란?

“인라인 함수 안에서 특정 람다 파라미터만 인라인하지 않도록 예외 처리”

사용 배경

  • inline 함수 안에서는 기본적으로 모든 람다 파라미터가 인라인됨.
  • 하지만 람다를 나중에 저장하거나 다른 함수에 전달해야 한다면, 인라인되면 안 되므로 noinline을 붙여야 함.
  • 객체 생성시 noinline이 붙는다면 선언할때마다 계속 생성함

✅ 예시

inline fun doSomething(
    inlineBlock: () -> Unit,
    noinline normalBlock: () -> Unit
) {
    inlineBlock()           // 인라인됨
    val ref = normalBlock   // ❌ 일반 람다는 저장 불가 → noinline 덕분에 가능
    ref()                   // 나중에 호출 가능
}

정리

  • inline 함수 내부에서 람다를 저장/전달해야 한다면 → noinline
  • 즉, “인라인은 하지 말고 일반 변수처럼 써라.”

3️⃣ crossinline — 비지역 반환 금지 + 안전한 컨텍스트 호출 허용

“인라인 함수 안의 람다를 다른 컨텍스트(비동기, 콜백 등) 에서 호출할 수 있도록 허용하되,

비지역 반환은 컴파일 단계에서 금지시킴”

✅ 예시

inline fun runAsync(crossinline block: () -> Unit) {
    Thread {
        block() // 다른 스레드(비동기) 안에서 실행
    }.start()
}

fun main() {
    runAsync {
        println("Running in background")
        // return ❌ 불가능 (비지역 반환 금지)
        return@runAsync ✅ 가능 (지역 반환)
    }
}

핵심 의미 두 가지

  1. 컴파일 타임에 비지역 반환을 차단

    → 다른 컨텍스트에서 return이 호출돼 프로그램 흐름이 꼬이는 걸 방지

  2. 비동기 컨텍스트 허용

    → 람다가 스레드, 콜백, 리스너 안에서도 안전하게 실행 가능


4️⃣ 한눈에 보는 비교표

키워드인라인 여부비지역 반환 가능다른 컨텍스트 호출 가능람다 저장 가능주요 사용 목적
inline✅ 가능⚠️ 위험할 수 있음❌ 불가능성능 최적화, 호출 오버헤드 제거
noinline❌ 불가능✅ 가능✅ 가능람다를 저장하거나 전달해야 할 때
crossinline❌ 금지✅ 가능❌ 불가능비동기/리스너 컨텍스트에서 안전하게 호출

5️⃣ 함께 이해하면 좋은 개념: 비지역 반환 (Non-local return)

inline fun call(block: () -> Unit) {
    block()
    println("After block")
}

fun main() {
    call {
        println("Inside")
        return  // ✅ main()까지 빠져나감
    }
    println("This line never runs")
}

inline 함수이기 때문에 block() 내부의 return

바깥 함수(main) 까지 영향을 미침.

즉, 이것이 “비지역 반환(non-local return)”입니다.

crossinline을 붙이면 이런 식의 제어 흐름을 컴파일러가 막습니다.


6️⃣ 안드로이드 예시 — SearchView 검색어 리스너

SearchViewsetOnQueryTextListener() 콜백을

확장 함수로 더 간결하게 만들 수 있습니다.

inline fun SearchView.onQueryTextChanged(
    crossinline onQuery: (String) -> Unit
) {
    setOnQueryTextListener(object : SearchView.OnQueryTextListener {
        override fun onQueryTextSubmit(query: String?) = true

        override fun onQueryTextChange(newText: String?): Boolean {
            onQuery(newText.orEmpty()) // crossinline: 안전하게 콜백 호출
            return true
        }
    })
}

✅ 사용 예시

searchView.onQueryTextChanged { keyword ->
    // 실시간 검색어 추천
    adapter.submitList(allItems.filter { it.contains(keyword, ignoreCase = true) })
}

콜백이 익명 객체(다른 컨텍스트) 안에서 실행되므로crossinline을 써서 비지역 반환을 금지 + 안전한 호출을 허용.


7️⃣ 마무리 요약

키워드핵심 개념한 줄 정리
inline코드 인라인화, 호출 오버헤드 제거함수 호출을 복붙하듯 최적화
noinline인라인 제외, 람다 저장/전달 허용람다를 변수처럼 다뤄야 할 때
crossinline비지역 반환 금지, 다른 컨텍스트 호출 허용비동기/리스너 안에서 안전하게 람다 실행
비지역 반환인라인된 람다의 return이 바깥 함수까지 탈출crossinline으로 막을 수 있음
profile
한걸음이라도 제대로... 쓰임있는 앱을 만들자

0개의 댓글