Groo

Kotlin 코틀린의 다양한 함수 본문

프로그래밍 언어/Kotlin

Kotlin 코틀린의 다양한 함수

김주엽 2020. 1. 22. 02:33

안녕하세요, 오늘은 Kotlin 언어의 다양한 함수의 종류에 대해서 알아보려고 합니다.
Kotlin은 일반, 고차, 람다식을 포함한 익명, 인라인, 확장, 중위 등 다양한 함수들이 존재하고 있습니다.

🙆‍♂️ 익명 함수란 무엇인가?

익명 함수란 일반 함수이지만 이름이 없는 형태의 함수입니다. 물론 람다식 함수도 이름 없이 함수를 구성할 수 있지만 아래의 코드와 같이 이것은 일반 함수에서 이름만을 생략하고 사용하는 것입니다. 함수 선언 키워드는 fun만 존재하고 이름이 존재하지 않습니다.

fun(x : Int, y : Int) : Int = x + y

또한 익명 함수는 람다식과 같이 일반 변수에 값으로 대입이 가능합니다. 익명 함수의 자료형을 람다식 형태로 사용하면 변수는 람다식 함수처럼 사용할 수 있는 것입니다. 이것은 람다식 표현과 매우 유사하여 람다식과 비슷하게 이용을 할 수 있습니다.

val add : (Int, Int) -> Int = fun(x, y) = x + y // 변수에 익명 함수 대입
val result = add(10, 2) 

그럼 왜 람다식이 존재하지만 익명 함수를 또한 사용을 하는 것일까요? 람다식에서는 return, break 등과 같이 제어문을 사용하기 어렵지만 익명 함수는 일반 함수에서 이름만 제외된 것이기 때문에 조건식에 따라 함수를 중단하고 반환하는 등 다양한 역할을 수행하기에는 더욱 편리하기 때문입니다. 그렇기 때문에 필요한 상황에 따라 람다식과 익명 함수를 상황에 맞게 사용하는 것이 중요합니다.

🏹 인라인 함수란 무엇인가?

대부분의 함수들은 함수를 호출할 때 2번의 분기 과정을 거칩니다. 함수를 호출하고 반환하기 때문이죠, 하지만 인라인 함수는 코드의 성능을 높여주기 위해 분기 없이 함수의 본문 내용을 복사하여 코드의 성능을 높여줍니다. 인라인 함수는 함수의 본문이 복사되어 들어가기 때문에 대부분 람다식 매개변수를 가지고 있는 짧은 내용인 함수에서 동작을 합니다. 아래의 예시를 통해 설명하겠습니다.

fun main() {

    shortFunc(3){ println("First call : $it")}
    shortFunc(5){ println("Second call : $it")}
}

inline fun shortFunc(a : Int, out : (Int) -> Unit){
    println("Before calling out()")
    out(a)
    println("After calling out()")
}

위의 코드를 보면 shortFunc 함수를 2번을 호출하는 것처럼 보이지만 컴파일을 해보면 shortFunc 함수의 본문에 있는 내용이 main 블록 안에 2번 복사되고 있는 과정을 볼 수 있습니다. 즉 람다식 매개변수 out을 통해 순서대로 값이 출력되고 있습니다.

fun main() {

    shortFunc(3){ println("First call : $it")}
    shortFunc(5){ println("Second call : $it")}
}

inline fun shortFunc(a : Int, noinline out : (Int) -> Unit){ // noinline 키워드 사용
    println("Before calling out()")
    out(a)
    println("After calling out()")
}

인라인 함수는 코드가 너무 길거나 인라인 함수의 본문 자체가 너무 길면 컴파일러에서 성능 경고가 발생할 수도 있으며 성능에도 좋지 않을 수가 있습니다. 그렇다면 일부 람다식을 인라인 되지 않게 하려면 어떻게 해야 할까요? 다음과 같이 noinline 키워드를 사용한다면 그 람다식 함수를 인라인 즉 복사를 하는 과정을 거치지 않고 분기를 나누어 호출을 하는 과정을 거치는 것을 볼 수 있습니다.

🥽 확장 함수란 무엇인가?

저희가 자주 사용하는 클래스에는 다양한 멤버 매서드들이 존재합니다. 그런데 기존 멤버 매서드는 아니지만 기존의 클래스에 내가 원하는 매서드를 추가하고 즉 확장하고 싶을 때 코틀린에서는 클래스 안에 함수를 더 추가할 수 있는 확장 함수의 사용을 제공하고 있습니다. 예를 들어 String 클래스 안에 자신이 원하는 새로운 String 클래스의 맴버 매서드를 생성할 수 있다는 것입니다.

fun main() {
    val source = "Hello World!"
    val target = "Kotlin"

    println(source.getLongString(target)) // String 클래스의 getLongString 확장 함수 호출
}

fun String.getLongString(target : String) : String = if(this.length > target.length) this else target

위의 코드와 같이 String 클래스 안에 getLongString 맴버 매서드를 생성하였습니다. main 함수에서 source 변수의 속성으로 호출을 하며 즉 String 변수의 속성으로 호출합니다. getLongString 매서드에서 this는 main 매서드에서 호출한 source 변수를 의미하며 문자열의 대소 관계를 비교하여 다시 String 문자열로 반환을 하는 간단한 매서드인 것을 알 수 있습니다.

🎯 중위 함수란 무엇인가?

중위 표현법이란 클래스의 멤버를 호출할 때 점과 소괄호를 붙이지 않음을 통해 직관적인 이름을 사용할 수 있는 표현방식입니다. 즉 중위 함수를 통해 일종의 연산자를 구현할 수 있다는 것이죠. 중위 함수를 이용하려면 아래의 3가지 조건을 만족해야 합니다.

 

중위 함수의 조건


1. 하나의 매개변수를 가져야 합니다.


2. 멤버 메서드 또는 확장 함수여야 합니다.

3. infix 키워드를 사용하여 함수가 정의되어야 합니다.

위의 조건 3가지가 모두 성립을 하여야만 중위 함수로 이용을 할 수 있다는 것입니다. 아래의 중위 함수 코드의 예시를 통해서 다시 한번 중위 함수에 대해서 알아보는 시간을 가지도록 하겠습니다. 아래의 코드 또한 별로 어렵지 않으며 조건에 모두 성립하고 있습니다.

fun main() {

    val multi = 3 multiply 10 // 점과 소괄호를 생략
    println("multi : $multi")
}

infix fun Int.multiply(a : Int) : Int = this * a // 1개 이상의 매개변수 및 infix 키워드

👍 글을 마치며

오늘은 Kotlin 언어의 다양한 함수들의 종류에 대해서 알아보았습니다. Kotlin은 앞에서도 말했듯이 다양한 종류의 함수들을 가지고 있으며 이 함수들을 잘 활용을 한다면 코드의 효율성이 높아지고 유용할 것이라고 생각을 하였습니다. 하지만 다른 언어들과 달리 많이 경험해보지 못하고 익숙하지 않아 많이 어색하기는 하지만 람다식을 포함한 다양한 함수들을 잘 사용한다면 좋을 것 같습니다. 

 

참고 : Do it 코틀린 프로그래밍

Comments