F.R.I.D.A.Y.

Kotlin: 16 고차 함수 본문

DEV/Kotlin

Kotlin: 16 고차 함수

F.R.I.D.A.Y. 2020. 7. 22. 01:17
반응형

 이전 시간에 우리는 언어의 패러다임을 배웠습니다. 그 내용에는 일급 객체에 대한 내용도 함께 실려 있는데요, 이번 시간에는 일급 객체, 특히나 고차 함수에 대해 알아보겠습니다.


고차 함수

 먼저 고차 함수가 무엇인지 알아보겠습니다. 고차 함수는 "함수를 인자로 사용하거나, 함수를 반환하는 함수"입니다. 달리 이야기하면, 일급 객체(일급 함수)를 서로 주고받을 수 있는 함수가 있다면 그 함수가 고차 함수가 되는 것입니다.

fun main(args:Array<String>){
    TestFunc()
}

fun TestFunc(): Int{
    return sum(2, 4)
}

fun sum(a:Int, b:Int) = a + b

 이 코드에서는 TestFunc()가 고차 함수의 조건을 만족하고 있습니다. 함수를 인자로 활용하지는 않지만, sum()을 이용해 값을 반환하고 있기 때문에 고차 함수라 할 수 있습니다.

 

반환값으로 사용하기

 특정 값을 반환하기 위해서는 우리는 return 키워드를 사용했습니다. 따라서 함수를 반환값으로 사용하고 싶다면 return 키워드 다음에 작성하면 가능합니다. 

 

인자에 사용하기

 함수의 데이터 타입

 함수를 인자에 사용하는 방법은 함수에 매개 변수를 작성하는 방법과 유사합니다. kotlin에서 함수 인자를 작성할 때는 아래와 같았습니다.

fun FuncName(ArgName:DataType)

 일급 객체(일급 함수)도 결국은 데이터입니다. 따라서 함수에 매개변수를 작성하는 방법과 동일하게 일급 객체(일급 함수)도 동일하게 작성하면 됩니다.

 

fun TestFunc(vabs:(Int)->Int, value:Int){
    println("vabs(${value}) = ${vabs(value)}")
}

fun main(args:Array<String>){
    TestFunc(::abs, -4)
}

fun abs(v:Int): Int = if(0 < v) v else -v

 안내: TestFunc(::abs, -4) 코드 중, ::abs에 대한 내용은 다음 문단에서 다룹니다.

 

 abs의 매개변수 인자 v(Int)와 반환형 Int는 함수의 데이터 타입을 작성할 때 필요한 정보입니다. 함수의 데이터 타입은 아래와 같습니다.

(일급 함수의 매개변수 인자의 데이터 타입 목록) -> 반환할 데이터 타입

 TestFunc 함수의 첫 번째 매개 변수 vabs의 자료형 (Int)->Int는 abs 함수와 매치했을 때 아래와 같습니다.

같은 색으로 밑줄 쳐진 것끼리 매칭 됨

 

일반 함수를 위한 콜론

 윗 문단의 테스트 코드를 보면 다음 코드가 존재합니다.

fun main(args:Array<String>){
    TestFunc(::abs, -4)
}

 다른 것들은 그렇다 치고, abs 앞에 존재하는 두 개의 콜론(:)은 무엇일까요? 두 개의 콜론을 우리는 함수 참조 기호라 일컫습니다. 일반 함수는 다음 문단에서 설명할 람다식이 아니기에 함수 참조 기호를 통해 소괄호를 생략한 채 인자에 값으로 넣을 수 있습니다.

 소괄호는 함수의 작동을 의미한다고 볼 수 있습니다. 따라서 이렇게 함수 앞에 콜론 두 개를 붙이게 되면 함수의 진행 방식을 바꿀 수 있습니다.

fun main(args:Array<String>){
    TestFunc(abs, -4)
}

 이렇게 콜론을 붙이지 않고 사용하게 되면, abs는 일반 함수이므로 실행을 위해 소괄호를 붙여주어야 합니다. 따라서 실행은 TestFunc로 진입하기 전, 값을 결정하고 들어가게 되는 것입니다. 그러나 ::abs와 같이 작성하게 되면, abs 함수를 TestFunc 함수의 안에서 실행하도록 순서를 변경할 수 있습니다. 만일 일반 함수가 TestFunc 함수 안에서 작동이 되어야 한다면, 인자의 함수 앞에는 꼭 두 개의 콜론이 들어가야 합니다.

 

 

함수를 인자로 넘기는 이유

왜 함수를 인자로 넘기는 걸까요? 다음의 함수 A가 있다고 해봅니다.

fun A(v1:Int, v2:Int):Boolean = if(v1 > v2) true else false

이때 v1과 v2가 특정 값일 때 추가 작업을 해야 한다면 아래 같은 code 구성을 해야 할 것입니다.

fun A(v1:Int, v2:Int):Boolean{
    if(v1 == 4){
        // v1이 4일 때 작업
    }
    
    if(v2 == 5){
        // v2가 5일 때 작업
    }
    
    if(v1 > v2) return true
    else return false
}

 어떠한 경우든 동일한 작업을 시행하는 함수라면 위 코드처럼 작성해도 괜찮을 것입니다. 정상적으로 동작하기 때문이죠. 그러나, 동일 작업을 해야 하는 경우가 아니라면 비슷한 일을 하는 함수를 여러 개 만들어야 합니다.

 이때, 각 상황에 맞는 작업을 인자로 받게 한다면 코드의 재사용성이 증가하겠죠?

 

 다른 하나는 기존에 제공되는 함수를 내 함수의 중간에 넣을 수 있기 때문입니다. println, readLine 같은 함수처럼 기본적으로 제공되는 함수들이나 다른 개발자들이 제공하는 함수[# 예컨대 API, 혹은 오픈소스 라이브러리 등]를 넣어 작동시킬 수 있습니다.

 이 방식이 제공되지 않으면 기존의 함수, 혹은 다른 사람이 만든 함수들을 내 코드에 동적으로 넣을 수 없기 때문에 앞서 설명한 것과 마찬가지로 각 상황에 맞는 함수를 여러 개 만들어야 합니다.


Next.

 여러 차례 밀리다 이제야 소개할 수 있게 되겠네요. 다음 포스트에서 소개할 문법은 람다식(Lambda Expression, λ-Expression)입니다.

 

Kotlin: 17 람다식(Lambda Expression) part1. Basic

 이전 시간에 우리는 고차 함수에 대해 배웠습니다. 함수를 인자로 넘기는 방법도 배웠죠. 그런데 이전 시간의 범위에는 포함되지만, 조금 더 많은 이야기를 위해 따로 빼놓은 것이 있습니다. ��

pang2h.tistory.com

# index

728x90
반응형
Comments