- inline 한정자의 역할은 컴파일 시점에 '함수를 호출하는 부분'을 '함수의 본문으로 대체' 하는 것
- inline 한정자 사용의 장점
- 타입 아규면트에 reified 한정자를 붙여서 사용할 수 있음
- 함수 타입 파라미터를 가진 함수가 훨씬 빠르게 동작
- 비지역(non-local) 리턴을 사용할 수 있음
타입 아규먼트를 reified로 사용할 수 있다
- 제네릭의 경우 컴파일 타임에 타입정보가 사라짐
- 따라서 타입 파라미터에 대한 연산에 오류가 발생
- 함수를 인라인으로 만들면, 이러한 제한을 무시할 수 있음
- 함수 호출이 본문으로 대체되므로, reified 한정자를 지정하면, 타입 파라미터를 사용한 부분이 타입 아규먼트로 대체
함수 타입 파라미터를 가진 함수가 훨씬 빠르게 동작한다
- inline 한정자를 붙이면 함수 호출과 리턴을 위해 점프하는 과정과 백스택을 추적하는 과정이 없기 때문에 조금 더 빠르게 동작하는 것
- 함수 파라미터를 가지지 않는 함수에서는 inline 한정자 유무에 따른 차이가 큰 차이를 발생시키지 않는다.
- 함수 리터럴을 사용해 만들진 종류의 객체는 어떤 방식으로든 저장되고 유지되어야 함
- 코틀린/JVM 에서는 JVM 익명 클래스 또한 일반 클래스를 기반으로, 함수를 객체로 만들어 낸다
class LambdaExample {
val lambda: () -> Unit = {
print("lambda")
}
}
위의 예제는 아래와 같이 컴파일 된다.
- 함수 본문을 객체로 wrapping 하기 때문에 코드의 속도가 느려진다.
인라인 함수와 인라인 함수가 아닌 함수의 중요한 차이는 함수 리터럴 내부에서 지역 변수를 캡쳐할 때 확인할 수 있다
- 인라인이 아닌 람다 표현식에서는 표현식 바깥의 지역 변수를 직접 사용할 수 없다.
- 람다 표현식이 객체로 랩핑 되기 때문
- 따라서 지역 변수는 컴파일 과정 중에 레퍼런스 객체로 랩핑되고, 람다 표현식 내부에서 이를 사용
class Repeat {
private fun repeat(action: () -> Unit) {}
fun test() {
var l = 1L
repeat {
l += 1
}
}
}
비지역적 리턴을 사용할 수 있다
- 함수 리터럴이 컴파일될 때, 함수가 객체로 wrapping 되기 때문에 내부에서 리턴을 사용할 수 없다
- 함수가 다른 클래스에 위치하기때문에 return을 사용해서 main으로 돌아올 수 없기 때문
- inline을 사용하면 함수가 main 함수 내부에 박히기 때문에 return을 사용할 수 있다.
inline 한정자의 비용
- 인라인 함수는 재귀적으로 동작할 수 없다
- 인라인 함수는 더 많은 가시성 제한을 가진 요소를 사용할 수 없다
- public 인라인 함수 내부에서는 private과 internal 가시성을 가진 함수와 프로퍼티를 사용할 수 없다
- inline 한정자를 남용하면 코드의 크기가 쉽게 커진다
crossinline과 noinline
함수를 인라인으로 만들고 싶지만, 어떠한 이유로 일부 함수 타입 파라미터는 inline으로 받고 싶지 않은 경우가 있을 수 있다
- crossinline
- 아규먼트로 인라인 함수를 받지만, 비지역적 리턴을 하는 함수는 받을 수 없게 만든다
- 인라인으로 만들지 않은 다른 람다 표현식과 조합해서 사용할 때 문제가 바생하는 경우 활용
- noinline
- 아규먼트로 인라인 함수를 받을 수 없게 만든다
- 인라인 함수가 아닌 함수를 아규먼트로 사용하고 싶을 때 활용
class InlineKeywordExample {
inline fun requestNewToken(
hasToken: Boolean,
crossinline onRefresh: () -> Unit,
noinline onGenerate: () -> Unit
) {
if (hasToken) {
httpCall("get-token", onGenerate)
} else {
httpCall("refresh-token") {
onRefresh()
onGenerate()
}
}
}
fun httpCall(url: String, callback: () -> Unit) {
}
}
'Reading Record > 이펙티브 코틀린' 카테고리의 다른 글
[이펙티브 코틀린] Item 48. 더 이상 사용하지 않는 객체의 레퍼런스를 제거하라 (0) | 2022.06.13 |
---|---|
[이펙티브 코틀린] Item 47. 인라인 클래스의 사용을 고려하라 (0) | 2022.06.13 |
[이펙티브 코틀린] Item 45. 불필요한 객체 생성을 피하라 (0) | 2022.06.12 |
[이펙티브 코틀린] Item 38. 연산 또는 액션을 전달할 때는 인터페이스 대신 함수 타입을 사용하라 (0) | 2022.06.07 |
[이펙티브 코틀린] Item 37. 데이터 집합 표현에 data 한정자를 사용하라 (0) | 2022.06.07 |