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

Kotlin: 16 고차 함수 본문

DEV/Kotlin

Kotlin: 16 고차 함수

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

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


Index

  • 고차 함수
    • 반환값으로 사용하기
    • 인자에 사용하기
      • 함수의 데이터 타입
      • 일반 함수를 위한 콜론
      • 함수를 인자로 넘기는 이유
  • Next.

Script from F.R.I.D.A.Y


고차 함수copy^

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

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

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

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

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

 

반환값으로 사용하기copy^

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

 

인자에 사용하기copy^

 함수의 데이터 타입copy^

 함수를 인자에 사용하는 방법은 함수에 매개 변수를 작성하는 방법과 유사합니다. 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 함수와 매치했을 때 아래와 같습니다.

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

 

일반 함수를 위한 콜론copy^

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

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

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

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

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

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

 

 

함수를 인자로 넘기는 이유copy^

왜 함수를 인자로 넘기는 걸까요? 다음의 함수 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 같은 함수처럼 기본적으로 제공되는 함수들이나 다른 개발자들이 제공하는 함수[1]를 넣어 작동시킬 수 있습니다.

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


Next.copy^

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

 

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

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

pang2h.tistory.com

728x90
반응형
Comments