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

Kotlin: 14 인라인 함수와 익명 함수 본문

DEV/Kotlin

Kotlin: 14 인라인 함수와 익명 함수

F.R.I.D.A.Y. 2020. 4. 6. 23:36
반응형

 

 

 함수 파트에서 떨어트리고 지금 나온 인라인&익명 함수입니다. 두 문법은 사실 함수 파트를 다룰 때 이어서 함께 작성해도 되지 않았을까 싶은 생각이 듭니다. 이미 지나가버린 걸 어떻게 하겠어요? 시작합니다.


함수의 준비

 우리가 특정 작업을 한다고 했을 때, 사전 작업으로 무엇을 할까요? 먼저 작업에 필요한 물건을 가져오거나, 환경을 조성하겠죠. 제가 블로그에 글을 쓰기 위해 컴퓨터를 켜고 로그인을 하는 것처럼 말이죠.

 우리 프로그램도 각 작업을 하기 위해서는 사전 작업이 필요합니다. 프로그램은 거대한 하나의 구조물이라 볼 수 있습니다. 이 거대한 구조물을 하나하나 쪼갠 것이 함수죠.

스택 작업

 함수 파트에서 봤지만 함수에는 인자를 넘겨줄 수 있습니다. 이렇게 인자로 전달된 값들은 매개 변수의 값이 되는데요. 이 값들은 어떻게 관리될까요? 간단히만 말하면, 탑을 쌓듯이 관리하게 됩니다.[# 이를 스택 프레임이라 합니다. 자세한 내용은 C 언어를 기반으로 설명한 이 포스트를 참고하세요. 실제 관리 구조를 설명하는 부분은 코드가 아닌 이미지를 이용하기에 C 언어를 이용하지 않더라도 이해할 수 있을 것입니다.]

 

 A 함수에서 B 함수를 호출하면 B 함수로 진입하게 됩니다. 이때, A 함수에서 B 함수로 넘어가면서 발생하는 사전 작업[# 이렇게 작업을 위한 작업을 오버헤드라고 부릅니다.]이 있습니다. 이 과정은 큰 힘을 들이지는 않지만, 경우에 따라서는 속도에 유의미한 영향을 끼치기도 합니다.


인라인 함수(inline function)

 그래서 나온 것이 바로 inline 키워드와 이를 이용한 inline 함수입니다.

구조

 inline 함수는 기존의 함수 선언에 fun 키워드 앞에 inline이라는 키워드가 추가됩니다.

inline fun functionName(parameters) {....

사용

 sum 함수가 있다고 해보겠습니다.

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

fun main(args: Array<String>){
    var total = 0
    
    for(v in 1..10) total = sum(total, v)
    
    println(total)
}

 이 sum 함수는 인라인 함수가 아니기에, 함수를 사용했을 때 오버헤드가 존재합니다.

 

 

 그러나 이 sum 함수를 inline 함수로 변경해봅니다.

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

 그럼 inline 키워드에 의해 컴파일 시 sum이 호출되는 영역으로 sum 함수가 복사됩니다. 물론, 함수 구조 전체가 복사가 되진 않지만요. 아래처럼 복사가 이루어진다고 볼 수 있습니다.

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

fun main(args: Array<String>){
    var total = 0
    
    for(v in 1..10) total = a + b // 인라임 함수는 이와 유사하게 복사
    
    println(total)
}

 요점

 inline 함수의 요점은 바로 코드의 복사입니다. 코드의 복사로 작업이 진행되기 때문에 만일 inline 함수를 여러 곳에서 호출했다면 컴파일할 때는 호출한 곳에 inline 함수의 명령어가 그대로 복사가 된, 변환된 코드를 컴파일하게 됩니다. 따라서 그만큼 프로그램의 용량이 늘어나게 됩니다.


익명 함수(Anonymous function)

 함수 중에는 이름이 없는 익명 함수도 존재합니다. 말 그대로 '이름'만 없습니다. 그래서 구조가 이름의 유무만 빼고 다 똑같지요.

구조

fun(parameters):returnType{
    // commands
}

 보시다시피 fun 키워드와 (parameters) 사이에 이름이 존재할 자리에 아무것도 존재하지 않습니다. 이를 익명 함수라고 부릅니다.

호출 방법

 이름이 없는 함수는 어떻게 불러들일까요? 이때 필요한 것이 변수입니다. 코틀린에선 변수가 함수를 가리킬 수 있습니다.

val testFunc:(Int, Int) -> Int = fun(a, b) = a + b

 이 코드는 testFunc라는 변수에 익명 함수를 바인딩[# 대표적으로는 변수에 값을 연결 짓는 행위를 말합니다. 이 경우처럼 말이죠.]하는 코드입니다. 하나하나 살펴보겠습니다.

val testFunc

 아시다시피 변수를 선언하는 코드입니다.

(Int, Int) -> Int

 변수를 선언할 때는 자료형을 함께 작성해주어야 합니다. 이것이 바로 현재 testFunc 변수에 바인딩하려는 익명 함수의 자료형이라 볼 수 있습니다.

첫 번째 등호(Int = fun)

변수 testFunc에 익명 함수를 대입하겠다는 대입 연산자입니다.

fun(a, b)

 익명 함수의 정의입니다.

= a + b

 축약형으로 표현된 함수의 작업 명령어입니다. 축약 식이 아닌 기본식으로 표현할 때는 아래처럼 표현됩니다.

val testFunc = fun(a:Int,b:Int):Int{
    return a + b
}

 위와 같이 기본형으로 모든 매개변수, 반환형에 타입을 명시한 경우에는 변수 testFunc의 자료형을 따로 작성하지 않아도 됩니다.

왜 사용하는가

 사실 익명 함수는 여태 배운 것으로는 왜 사용하는지에 대한 의구심을 품을 수 있습니다. 이 내용은 나중에 배울 람다식(Lambda expression)을 배우면서 다시 알아보겠습니다.

 간단히만 설명하면, 람다식이란 문법에는 제약이 몇 가지 존재합니다. 이 제약을 무시하고 사용하기 위해서 익명 함수를 사용한다고 보면 될 것 같습니다.

 이렇게 람다식 대신 익명 함수를 사용할 수 있는 이유는 익명 함수를 단순화했을 때, 그 모양이 람다식과 유사하기 때문입니다.


 다음 시간에는 람다식에 대해 알아봅니다. 여태 공부한 내용들보단 어려울 수 있습니다.[# 사실 어려울 겁니다. 람다식을 다루면서 고차 함수를 함께 다룰 예정이니까요.] 그나저나 작업이 지연되서 포스트를 못하고 있네요... :( 빨리 작업이 마무리 되어야할텐데..

 람다식을 배우기 위한 선행 지식이 있다고 생각해 람다식을 후순위로 미루었습니다.

Next.

 

Kotlin: 15 함수형 프로그래밍

 이전 파트의 끝머리에서 15번째 포스트는 람다식이 될 것이라고 했습니다. 그러나 람다식을 배우기 전에 꼭 알아두어야 할 필요가 있다고 생각한 것이 생겨서 람다식을 후순위로 미루게 되었��

pang2h.tistory.com

# index

728x90
반응형

'DEV > Kotlin' 카테고리의 다른 글

Kotlin: 16 고차 함수  (0) 2020.07.22
Kotlin: 15 함수형 프로그래밍  (1) 2020.06.06
Kotlin: 13 예외 처리  (1) 2020.04.05
Kotlin: 12 흐름 제어하기  (0) 2020.04.04
Kotlin: 11 반복문-while, do-while  (0) 2020.04.03
Comments