고차 함수 는 매우 유용하며 실제로 reusability
코드를 향상시킬 수 있습니다 . 그러나 사용에 대한 가장 큰 우려 중 하나는 효율성입니다. Lambda 표현식은 클래스 (일반적으로 익명 클래스)로 컴파일되며 Java에서 객체 생성은 무거운 작업입니다. 함수를 인라인으로 만들어 모든 이점을 유지하면서 고차 함수를 효과적으로 사용할 수 있습니다.
여기에 인라인 함수 가 그림으로 나옵니다.
함수가로 표시되면 inline
코드 컴파일 중에 컴파일러가 모든 함수 호출을 함수의 실제 본문으로 바꿉니다. 또한 인수로 제공된 람다 식은 실제 본문으로 대체됩니다. 함수로 취급되지 않고 실제 코드로 취급됩니다.
간단히 말해서 :- 인라인-> 호출되는 대신 컴파일 타임에 함수의 본문 코드로 대체됩니다.
Kotlin에서는 함수를 다른 함수 (소위 고차 함수라고 함)의 매개 변수로 사용하는 것이 자바에서보다 더 자연스럽게 느껴집니다.
하지만 람다를 사용하면 몇 가지 단점이 있습니다. 익명 클래스 (따라서 객체)이기 때문에 메모리가 필요합니다 (앱의 전체 메서드 수에 추가 될 수도 있음). 이를 방지하기 위해 메서드를 인라인 할 수 있습니다.
fun notInlined(getString: () -> String?) = println(getString())
inline fun inlined(getString: () -> String?) = println(getString())
위의 예에서 :-이 두 함수는 정확히 같은 일을합니다-getString 함수의 결과를 출력합니다. 하나는 인라인되고 하나는 그렇지 않습니다.
디 컴파일 된 자바 코드를 확인하면 메서드가 완전히 동일하다는 것을 알 수 있습니다. 인라인 키워드는 코드를 호출 사이트에 복사하라는 컴파일러에 대한 명령이기 때문입니다.
그러나 아래와 같이 다른 함수에 함수 유형을 전달하는 경우 :
//Compile time error… Illegal usage of inline function type ftOne...
inline fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int, ftTwo: (Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
이를 해결하기 위해 다음과 같이 함수를 다시 작성할 수 있습니다.
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int, ftTwo: (Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
아래와 같은 고차 함수가 있다고 가정합니다.
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
여기서 컴파일러는 람다 매개 변수가 하나만 있고 다른 함수에 전달하는 경우 인라인 키워드를 사용하지 않도록 지시합니다. 따라서 위의 함수를 아래와 같이 다시 작성할 수 있습니다.
fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
참고 :-인라인 함수에만 사용할 수 있으므로 noinline 키워드도 제거해야했습니다!
다음과 같은 기능이 있다고 가정합니다 .-- >
fun intercept() {
// ...
val start = SystemClock.elapsedRealtime()
val result = doSomethingWeWantToMeasure()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
// ...}
이것은 잘 작동하지만 함수 로직의 핵심이 측정 코드로 오염되어 동료가 진행중인 작업을 더 어렵게 만듭니다. :)
인라인 함수가이 코드를 도울 수있는 방법은 다음과 같습니다.
fun intercept() {
// ...
val result = measure { doSomethingWeWantToMeasure() }
// ...
}
inline fun <T> measure(action: () -> T) {
val start = SystemClock.elapsedRealtime()
val result = action()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
return result
}
이제 측정 코드 줄을 건너 뛰지 않고 intercept () 함수의 주요 의도를 읽는 데 집중할 수 있습니다. 또한 우리가 원하는 다른 장소에서 해당 코드를 재사용 할 수있는 옵션의 혜택을받습니다.
인라인을 사용하면 measure (myLamda)와 같은 람다를 전달하는 대신 클로저 ({...}) 내에서 람다 인수를 사용하여 함수를 호출 할 수 있습니다.