오늘은 코틀린의 함수에 대해서 살펴보도록하자.

함수

함수 선언 및 사용

함수 선언은 자바와는 달리 fun을 사용해서 함수를 선언한다.

fun function(x: Int): Int {
    return x * 2
}

위와 같은 함수가 있을 경우 사용법은 아래와 같다.

val result = function(2)
println(result)

쓰는 법은 일반 다른 언어와 비슷한 문법을 가지고 있다.
또한 위의 함수는 expression 으로도 나타낼 수 있다.

fun function(x: Int) = x * 2

expression으로 쓸 경우에는 return 타입을 명시해주지 않아도 되며 return 키워드는 사용하지 않아야 한다.

Infix notation

infix 키워드를 사용해서 중위(Infix) 표현으로 사용할 수 도 있다.

fun Int.multiply(x: Int): Int {
    return this * x
}

위의 코드는 Int를 확장한 확장 함수이다. 간단하게 생각하면 Int 클래스의 함수를 더 추가 한다고 생각하면 되겠다.

val multiply = 3.multiply(10)

그럼 위와 같이 확장함수를 이용해서 간단하게 만든 multiply 를 사용할 수 있다. 중위 표현으로 변경하면 다음과 같다.

infix fun Int.multiply(x: Int): Int {
    return this * x
}

위와 같이 infix 키워드를 사용하면 중위 표현을 사용할 수 있다.

val multiply = 3 multiply 10

Default Arguments

함수의 파라미터(인자)에 기본값을 정의해 줄 수도 있다.

fun defaultArgumentsFun(x: Int = 100, y: Int = 200) {
    println(x + y)
}

위의 함수의 파라미터에는 x = 100 y = 200 으로 기본값으로 정의해 두었다.

defaultArgumentsFun()

위와 같이 사용할 수 있는데 파라미터가 없이 함수를 사용할 경우에는 기본값인 x에는 100이 y에는 200이 들어간다.

defaultArgumentsFun(100, 200)

위의 두개의 함수 사용은 같다고 볼 수 있다.

Named Parameters

함수의 파라미터는 함수를 호출 할 때 이름을 지정해 줄수 있다. 파라미터의 개수가 많거나 기본 값을 가진 경우에 사용하면 매우 유용하다.

fun namedParametersFun(x: Int = 100, y: Int = 200, z: Int) {
    println(x + y + z)
}

위와 같은 함수가 정의 되어 있을 경우에도 (z는 기본값이 없다.) Named Parameters를 사용할 수 있다. 사용 법은 아래와 같다.

namedParametersFun(x = 200, z = 100)

함수를 호출할 때 해당하는 이름을 지정해주면 된다. 당연히 z의 경우에는 기본값이 없기에 무조건 넣어줘야한다.

namedParametersFun(x = 200)

위와 같이 호출 할 경우에는 컴파일 에러가 발생한다.

Unit-returning functions

Unit은 어떠한 값도 리턴 하지 않는 것을 의미한다. 자바의 void와 비슷한 의미를 갖고 있다.
Unit을 리턴할 경우에는 리턴 타입을 명시해주지 않아도 된다.

fun unitReturnFun(x: Int) : Unit{
    println(x)
}

위의 코드는 Unit을 리턴하는 (리턴 값이 없는) 코드이다. 위의 코드는 Unit을 생략해도 된다.

fun unitReturnFun(x: Int) {
    println(x)
}

위와 같이 사용해도 컴파일 에러가 나지 않는다.

Variable number of arguments (Varargs)

코틀린에서도 자바와 같이 가변인자를 지원한다.

public static <T> void varargsParameters(T... ts){
  for(T t: ts){
    System.out.println(t);
  }
}

자바의 경우에는 타입뒤에 ...을 사용해서 가변인자로 만들 수 있다. 코틀린의 경우에는 vararg 키워드를 사용해서 만들수 있다. 위 자바 코드를 코틀린으로 바꾼다면 아래와 같다.

fun <T> varargsParametersFun(vararg ts: T) {
    for (t in ts){
        println(t)
    }
}

Higher-Order Functions and Lambdas

자바와 비슷하다. 코틀린은 고차함수도 사용가능하며 람다 표현식도 가능하다. 자바8을 사용하는 개발자라면 쉽게 다가갈 수 있다.
Higher-Order Functions은 파라미터로 함수를 받거나 함수를 리턴하는 함수이다.

잠깐 언급만 하고 가자. 일급언어의 조건은 다음과 같다.
1. 함수를 변수나 데이터 구조안에 담을 수 있다.
2. 함수를 파라미터로 전달 할 수 있다.
3. 함수를 반환(리턴) 값으로 사용할 수 있다.

위의 3가지를 만족하면 일급언어가 될 수 있다. 자바8도 3가지를 만족해서 일급 언어라고 할 수 있다. 메서드 레퍼런스가 영 맘에 안들어도 일단 만족은 하니…

아래 코드를 보자.

val list = mutableListOf(1, 2, 3, 4, 5)
val doubled = list.map { i -> i * 2 }

위의 코드는 고차 함수의 간단한 예이다. map은 함수를 파라미터로 받고 있다. 실제 코드는 아래와 같다.

public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

위에서 봤듯이 람다의 문법은 자바와 비슷하다. 다른 점이 있다면 () 대신 {} 감싸주는 부분이 다르다. 자바와는 조금 다르게 단일 파라미터에 it 이라는 명을 사용해서 조금더 간단하게 만들 수 있다. 위에 코드를 it을 사용해 바꾸어 보면 다음과 같다.

val list = mutableListOf(1, 2, 3, 4, 5)
val doubled = list.map { it * 2 }

-> 도 생략하고 조금더 간단해 졌다.

코틀린의 중요한 문법은 이정도로 된 듯 싶다. 아직 많긴 하지만 나머지는 공식 문서를 보면서 한번씩 해보는 것이 좋겠다.
다음시간에는 마지막으로 기타 여러 사항을 간단간단하게만 살펴보고 끝내자. 그래도 어느정도 공부는 된 듯 싶다.

필자가 한달전 쯤에 spring boot를 코틀린으로 만든 간단한 웹페이지가 있다. spring boot를 쓰는 개발자들은 한번씩 간단하게 살펴봐도 괜찮을 거 같다. 근데 워낙 자바로 만든거나 코틀린으로 만든거나 비슷한거 같다.

spring-boot-kotlin-example

위의 github에서 소스를 확인가능하다.