Android 앱/Kotlin Language

kotlin 코틀린 - 고차함수, 람다함수, 익명함수

arvigoes 2020. 3. 10. 23:24

 고차함수 (High Order Function)

고차함수란 파라미터 또는 반환값으로 또 다른 함수가 사용되는 함수를 말합니다.

설명은 어렵지만 이해 하면 고차함수 자체는 어려운 내용이 없습니다.

함수를 변수처럼 입력으로 받을 수 있고 출력으로 사용 하는 함수 를 이르는 것일 뿐이니까요


fun add(num1:Int, num2:Int): Int {
    return num1 + num2
}

fun sub(num1:Int, num2:Int): Int {
    return num1 - num2
}

fun calc(func:(Int,Int)->Int, num1: Int, num2: Int) {
    var ret = func(num1, num2)
    println("Result $ret")
}

fun main(){
    calc(::add, 5, 3);
    calc(::sub, 5, 3);
}

여기에서 calc 라는 함수를 고차함수라고 합니다.

calc 는 계산기 함수로 첫번째 파라미터로 두수의 계산방식을 함수로 전달 받고, 두번째, 세번째 파라미터를 첫번째 계산 함수로 계산을 해서 결과를 출력해 줍니다.

 

add, sub 는 궂이 볼 필요 없을듯 하고 calc 함수를 좀 더 자세히 보겠습니다.

calc 함수의 첫번째 파라미터를 함수로 받기로 했습니다.

func:(Int, Int)->Int
이름:(파람1형, 파람2형)->반환형

파라미터 func 은 "파라미터로 Int 값 두개를 받고 Int 값을 반환 하는 함수" 이라는 뜻입니다.

함수의 형태를 규정 하는 내용입니다.

이에 따라 첫번째 파라미터에 입력가능한 함수도 제한이 됩니다.

add, sub 처럼 입력으로 Int 두개, Int 값을 반환하는 함수만이 첫번째 파람미터로 사용 할 수 있습니다.

calc(::add, 5, 3);

함수를 사용하는 방법입니다.

add 함수를 파라미터로 사용 하기위해 더블콜론(::) 을 사용 했습니다.

코틀린에서 더블롤론은 리플렉션을 위해 사용합니다.

리플렉션이란 코드를 작성하는 시점에는 런타임 시점의 컴파일된 바이트코드중에서 add라는 함수의 위치를 알 수 없기 때문에 런타임시의 바이트 코드를 이용해 add 함수의 값을 찾기 위해 사용합니다.

 

자 여기서 다시 add 라는 함수를 다시 한번 확인 해 보도록 하겠습니다.

fun add(num1:Int, num2:Int): Int {
    return num1 + num2
}

두 값을 더해주는 아주 간단한 함수 입니다.

궂이 이렇게 간단한 내용을 함수를 만들 필요 있을까요? 

이럴때 사용 하는 것이 람다 함수 입니다.

 

람다함수 (Lambda function)

람다함수 는 람다표현식 (lambda expression) 이라고 많이 부르는데, 이름이 없는 함수 정도로 이해 하시면 될듯합니다.

엄밀히 말하면 함수와도 차이가 있고, 또 익명함수도 분명히 따로 존재 합니다.

 

위에서 구현해서 고차함수에게 파라미터로 넘겼던 함수를 람다표현식으로 표현 해 보도록 하겠습니다.

람다함수는 그 자체가 고차함수 이므로 별도의 연산자(리플렉션) 없이도 바로 사용이 가능 합니다.

fun calc(func:(Int,Int)->Int, num1: Int, num2: Int) {
    var ret = func(num1, num2)
    println("Result $ret")
}
fun main(){
    val lambda_add : (Int, Int)->Int = {num1, num2 -> num1 + num2}
    calc(lambda_add, 5, 3)

    val lambda_sub = {num1 : Int, num2 : Int-> num1 - num2}
    calc(lambda_sub, 5, 3)

    calc({num1, num2 -> num1 * num2}, 5, 3);
}

lambda_add 와 lambda_sub 함수는 add 와 sub를 lambda 로 표현한 람다표현식 입니다.

비슷하지만 조금씩 차이가 있죠? 변수 타입 자동추론을 활용한 것이 추가 되어 lambda_sub 는 따로 변수에 타입을 적지 않았습니다.

 

그리고 마지막은 변수를 선언하지 않고 바로 calc 함수의 파라미터로 넘기는 방식입니다.

람다는 함수를 변수에 담을 수에 담아서 변수처럼 사용할 수 있습니다.

 

함수와 차이점을 보도록할까요?

우선은 가장 크게 이름이 없다는 점!

그리고 return 이 없습니다.

코틀린에서는 이름이 있는 함수나, 익명의 함수에서만 return 이 사용 될 수 있다고 되어 있습니다.

lamda 표현식은 익명함수 처럼 보이지만 lambda 표현식 이므로 익명함수는 아닙니다.

그러므로 lambda 표현식에서는 return 을 사용 할 수 없습니다.

return을 사용할 수 있는 경우도 있는데 이 부분에 대해서는 다음에 다뤄 보도록 하겠습니다.

기본적인 함수의 return 은 사용 할 수 없다로 생각 하시면 됩니다.

람다 함수에서는 함수 내용의 마지막 줄 결과가 반환값이 되므로 num1 + num2 의 결과가 반환됩니다.

반환이 없는데 반환된다라는 말도 좀 이상하지만 익숙한 표현이 반환이니 반환으로 이해 하고 넘어가는게 좋을 듯 합니다.

함수와 콜스텍 함수의 return 등에 대해 한번 심도 있게 다뤄 볼 필요가 있겠네요

 

익명함수(Anonymous function)

일반적인 선언으로는 익명함수는 선언 될 수 없습니다.

일반적인 함수 선언하는 공간에서 선언하게 된다면 function declaration must have a name 이라는 error 가 나옵니다.

fun (num1:Int, num2:Int):Int {		// function declaration must have a name error!!!
    return num1 + num2
}

 

그러면 어떻게 사용 해야 하는 걸 까요?

간단하게 익명함수 예제도 보도록 하겠습니다.

    calc(fun (num1:Int, num2:Int):Int{return  num1 + num2}, 5, 3);

Add 를 익명으로 구현한 예제 입니다.

fun 키워드로 함수를 선언하여 파라미터로 넘겼습니다.

익명 함수이므로 return 을 사용할 수 있는 조건을 충족하였습니다.

 

lambda 표현식과 함수는 비슷하지만 차이가 있습니다.

이부분을 숙지 하시고 사용하시면 차후에 새로운 내용이 추가 되거나 독특한 함수를 보더라도 이해가 빠르리라 생각합니다.