Kotlin 은 고차함수에 대한 문법을 지원한다.
고차함수를 사용한 함수는 런타임 오버헤드가 어느정도 발생하는데 이를 줄이기 위한 방법으로 Kotlin 은 Inline Function 을 지원한다.
고차함수란, 함수를 파라미터로 받거나 함수를 리턴하는 즉, 함수를 일급객체로 취급하는 함수를 말한다.
고차함수의 오버헤드
class InlineTestClass {
fun highOrderedFunction(a: Int, actionBlock: (a: Int) -> Int): Int {
actionBlock(a)
return a + 1
}
fun main() {
val result = highOrderedFunction(1) { a -> a * 2 }
println(result)
}
}
숫자와, 숫자 를 핸들링하는 어떤 함수를 받아서 처리하는 고차함수를 하나 정의해보았다.
위 함수를 컴파일하면, 아래와 같이 매 호출시마다 Function을 생성해서 전달하고, 고차함수 안에서 호출하는 java 코드가 생성된다.

매번 새 Function 을 생성하는만큼의 오버헤드가 발생하는 것이다.
이를 Inline 키워드를 사용해 해결할 수 있다.
Inline
class InlineTestClass {
inline fun highOrderedFunction(a: Int, actionBlock: (a: Int) -> Int): Int {
actionBlock(a)
return a + 1
}
fun main() {
val result = highOrderedFunction(1) { a -> a * 2 }
println(result)
}
}
기존 고차함수에 Inline 키워드를 부여하고 자바로 컴파일된 클래스를 보면?

main 함수로 inline 으로 정의한 고차함수와, 인자로 전달한 함수가 펼쳐져서 인라인 되었다.
이렇게 되면 굳이 매 메서드 호출마다 Function 을 생성하여 메모리를 할당하고 또 메서드 안에서 함수블럭을 실행할 메모리를 할당하는 오버헤드가 사라진다.
noinline
inline 함수는 위에서 보았듯, Function 을 생성하지 않고 코드를 펼쳐서 인라인 하는 개념이기 때문에,
또 다른 함수의 인자로 전달받은 함수를 전달할 수 없다.
이런식으로 전달 받은 인자 함수를 inline 하면 안되는 경우가 있는데, 이럴때 사용하는 것이 noinline 키워드이다.

inline fun highOrderedFunction(a: Int, noinline actionBlock: (a: Int) -> Int): Int {
highOrderedFunction_2(a, actionBlock)
return a + 1
}
fun highOrderedFunction_2(a: Int, actionBlock: (a : Int) -> Int) {
println(actionBlock(a))
}
이렇게 하면, 전달받은 함수도 다시 전달할 수 있게 된다.
(하지만 이 경우는 highOrderedFunction 을 inline 함수로 지정할 필요가 없게 되므로 IDE 나 정적분석 프로그램이 경고를 줄 것이다)
함수를 2개 이상 전달 받는 경우, 하나는 인라인하고 하나는 인라인하지 않는등의 방식으로 사용하면 된다.
refied
코틀린에는 inline 함수에만 사용할 수 있는 refied 라는 키워드가 있다.
fun <T> generic(c: Class<T>)
원래 제너릭 함수에서 전달받는 타입 T 는 컴파일 타임에는 존재하지만, 런타임에는 Type Eraser 에 의해 존재하지 않아
런타임에서 클래스의 타입에 접근하고 싶다면 Class<T> 를 인자로 넘겨야한다.
fun <T> generic() {
val a = "ㅋㅋㅋ"
assertTrue(a.javaClass === T::class.java) // 컴파일 오류
}
fun <T> generic(type: Class<T>) {
val a = "ㅋㅋㅋ"
assertTrue(a.javaClass === type) // true
}
inline fun <reified T> genericFunc()
하지만 inline 함수에서는 refied 키워드를 사용하여, 타입파라미터를 넘길 필요 없이, 함수 body 에서 T 타입에 대해 접근할 수 있다.
또한 is 키워드로 타입비교가 가능하다.
inline fun <reified T> generic() {
val a = "ㅋㅋㅋ"
assertTrue(a is T) // no compile error, True
}
위 코드는 아래와 같이 컴파일된다.

kotlin.jvm.internal 패키지에 존재하는 함수를 호출한다.
reified 타입 파라미터로 작성된 인라인 함수는 자바코드에 호출할 수 없다.
'Kotlin' 카테고리의 다른 글
| Kotlin 의 널 (Null) 을 다루는 방법 (0) | 2022.05.24 |
|---|---|
| Kotlin 에서 GraphQL-spqr 사용시, Companion Object 스키마 빌드 오류 (0) | 2022.05.02 |
| Mockk 으로 Kotlin 현재 시간 관련 로직 테스트하기 (0) | 2022.03.21 |