ABOUT ME

-

  • Kotlin) inline 함수와 고차함수 알아보기
    Kotlin 2020. 12. 15. 12:45

     

    고차함수(Higher order fuctions)

    • 인자가 함수이거나 함수를 리턴하는 함수
    • 코틀린에서 고차함수를 사용하면 추가적인 메모리 할당 및 함수호출로 Runtime overhead가 발생합니다.
     fun someMethod(a: Int, func: () -> Unit): Int {
            func()
            return 2 * a
     }
    
     fun main(args: Array<String>) {
            var result = someMethod(2) { println("Just some dummy fuction") }
            println(result)
     }

    inline 개념

    • inline fuctions는 내부적으로 함수 내용을 호출되는 위치에 복사하며, 고차함수의 Runtime overhead를 줄여줍니다.
    • 컴파일하는 동안 해당 함수의 모든 사용 부분이 본문으로 바뀌게 됩니다.
    • non-local return을 허용합니다.(caller function return 허용) -> return 값이 없이 return만 허용하는 것입니다.
    inline fun repeat(times: Int, action: (Int) -> Unit) {
         for (index in 0 until times) {
                action(index)
         }
    }
       
    repeat(10) {
    	print(it)
    }
    
    // 컴파일 시
    for (index in 0 until 10) {
    	print(index)
    }
    •  타입 인자의 구체화가 가능합니다.
    val any: Any = listOf<Any>()
    if (any is List<Int>) { /* Error */ }
    if (any is List<*>) { /* Ok */ }

     

    • inline은 재귀일 수 없습니다 -> 무한대로 호출됨, 런타임 에러 발생
    inline fun a() { b() }
    inline fun b() { c() }
    inline fun c() { a() }

    crossinline과 noinline

    crossinline
    • inline 함수이지만, non-local return을 허용하지 않습니다.(caller fuction return 허용하지 않음)
    fun main() {
    	repeat(10) {
    		print(it)
    		return // ERROR: Not allowed
    	}
    }

     

    noinline
    • 모든 인자를 inline으로 처리하고 싶지 않을 때, 인자 앞에 noinline 키워드를 사용하면 그 인자는 inline 키워드에서 제외됩니다.
    • 인자를 다른 함수의 인자로 전달할 수 있습니다.
    • inline 되지 않은 다른 함수의 인수로 사용하는 경우 사용됩니다.
    inline fun newMethod(a: Int, func: () -> Unit, noinline func2: () -> Unit) {
           func()
           someMethod(10, func2)
    }

    Reified 키워드를 사용하자

    • inline에서만 사용할 수 있는 reified 키워드가 있습니다. 
    • Generics 타입 T 앞에 써주면 됩니다.
    • reified를 사용하면 리턴 타입이 다른 함수를 오버로딩 할 수 있습니다.
    inline fun <reified T> getMsg(number: Int): T {
            return when (T::class) {
                String::class -> "The number is : $number" as T
                Int::class -> number as T
                else -> "Neither String and Int" as T
           }
     }

    위의 코드는 타입에 따라 리턴되는 타입이 다르도록 구현되어 있습니다. 아래와 같이 사용할 수 있습니다.

     val result: Int = getMsg(10)
     println("result :$result")
    
     val resultString: String = getMsg(100)
     println("result :$resultString")

    리턴되는 타입에 따라서 T가 결정되며 T에 따라서 리턴되는 객체가 달라집니다.


    Summary

    inline 함수를 주로 사용하는 경우는 다음과 같습니다.
    • 매우 자주 사용되는 함수 -> pirnt 함수
    • 구체화된 타입으로 된 타입 인수가 필요한 함수 
    • 컬렉션 처리 함수 -> map, filter, flatMap, joinToString
    • 범위 함수 -> apply, let
    • top-level 유틸리티 함수 -> repeat, run ,with
    • 명확하지 않은 의미를 지닌 타입, 다른 측정 단위를 가질 수 있는 타입
    • inline 함수로 API를 정의하는 경우는 거의 없습니다.

     


    Reference

    Kotlin - inline functions 이해하기

    반응형

    댓글

Designed by Me.