본문 바로가기
프로그래밍/kotlin

[kotlin] 코틀린 차곡차곡 - 3. 함수

by 사바라다 2021. 6. 6.

안녕하세요. 코틀린 차곡차곡 3번째 시간입니다. 오늘은 코틀린 함수의 기본에 대해서 알아보는 시간을 가져보도록 하겠습니다. 오늘 배울 부분은 자바의 method에 대응되는 코틀린의 function 이며 함수형프로그래밍과는 상관이 없음을 미리 알려드립니다.

function

코틀린에서 하나의 기능을 구현한 명령어의 집합을 함수(function) 이라고 부릅니다. 자바에서 메서드(Method)에 대응되는게 코틀린에서는 함수라고 생각해주시면 됩니다. 이런 코틀린의 함수의 구성은 아래와 같습니다.

  • 키워드(keyword) - 함수를 선언하시기 위해서는 먼저 fun 키워드를 통해 함수를 선언하겠다는 것을 명시하셔야합니다.
  • 함수 이름 - 그리고 한칸 띄우고 함수이름을 명시해야합니다.
    • 함수 이름은 자바와 마찬가지로 camelcase을 컨벤션으로 가져가고 있습니다.
  • 입력값 - 입력받을 값들을 나타냅니다. 이 값은 생략 가능하며, 여러 값일 경우 , 를 통해서 이어 붙일 수 있습니다.
    • 파라미터라고도 부릅니다.
  • 리턴 타입 - 해당 함수의 결과를 반환할 타입을 나타내는 부분입니다. 생략 가능하며 생략하면 Unit 타입의 아무것도 반환하지 않는 타입을 가지게 됩니다.
  • 리턴 값 ( 함수 본문(body) ) - { } 블럭 사이에 함수의 본문이 들어올 수 있습니다.
    • 함수 본문을 마무리할 때 return 키워드를 사용하여 값을 반환할 수 있습니다.

이렇게 만든 함수는 함수이름(입력값)을 이용하여 호출할 수 있습니다. 아래의 예제를 보도록 하겠습니다.

@Test
fun test2() {
    val double = double(5) // double 이름의 함수를 5의 입력값으로 호출
    println("값 = $double") // 결과 : 값 = 10
}

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

파라미터의 기본 값(Default Argument)

입력 값을 조금 더 전문적인 용어로 파라미터(parameter)라고 합니다. 코틀린에서 파라미터는 기본 값(Default Argument)을 가질 수 있습니다. 기본 값이란 파라미터에 입력되지 않은 값에 대해서 기본적으로 함수를 실행할때 그 값을 할당하여 사용하겠다는 것을 의미합니다.

사용 방법은 각 파라미터의 뒤에 =를 붙인 뒤 할당할 기본값을 입력하면 됩니다. 위의 예제를 조금 변형해서 기본값 예제를 만들어 보도록 하겠습니다.

@Test
fun test2() {
    val double = double() // 사용하는 곳에서 파라미터 입력하지 않음
    println("값 = $double") // 결과 : 값 = 20
}

fun double(x: Int = 10): Int { // 파라미터 x에 = 10 를 추가하여 입력값이 없으면 기본값으로 10을 할당한다고 명시
    return x * 2
}

이름 명시 파라미터(Named arguments)

함수를 호출하며 파라미터를 입력할 때 일반적으로 순서에 따라 값을 매핑합니다. 거기에 더해서 코틀린은 이름 명시 파라미터(Named Arguments)을 제공합니다. 이름 명시 파라미터란 함수를 호출 할 때 이름을 선언하고 거기에 값을 매핑하는 방식입니다. 이러한 방식을 사용하면 순서에 구애받지 않고 값을 전달 할 수 있습니다. 사용하는 방식은 아래의 코드와 같습니다.

@Test
fun test2() {
    val double = double(y = 2, x = 5) // double(5, 2) 와 동일
    println("값 = $double") // 결과 : 값 = 10
}

fun double(x: Int = 10, y: Int): Int {
    return x * y
}

단일 표현 식 (Single Expression)

만약 함수의 본문(Body)이 바로 return 값을 가질 때 이를 단일 표현식으로 나타낼 수 있습니다. 함수에는 원래 { }로 감싸줘야하고 return 키워드가 필수입니다. 하지만 단일 표현식에서는 이런 표현들을 생략할 수 있습니다. 아래 코드를 보시면 double_1과 double_2는 동일한 결과를 내는 동일한 함수 입니다.

@Test
fun test2() {
    val double1 = double_1(x = 5, y = 2)
    val double2 = double_2(x = 5, y = 2)
    println("값_1 = $double1") // 결과 : 값_1 = 10
    println("값_2 = $double2") // 결과 : 값_2 = 10
}

fun double_1(x: Int = 10, y: Int): Int {
    return x * y
}

fun double_2(x: Int = 10, y: Int): Int = x * y // 단일 표현식으로 {}과 return을 생략

추가로 단일 표현 식을 만들면 타입 추론을 통해 return 값이 Unit이 아니더라도 생략이 가능합니다. 따라서 아래의 식 또 동일한 결과를 가집니다.

fun double_3(x: Int = 10, y: Int) = x * y // 단일 표현식에서 return 타입 추론을 적용하여 : Int 생략

하지만 타입 추론은 이전 포스팅에서도 말했듯이 지양해야할 방법으로 판단되기때문에 명시 해주시는것을 권장드립니다.

지역 함수(Local Functions), 클로저(Closure)

코틀린은 함수안에서만 사용할 수 있는 지역 함수(Local Functions)를 지원합니다. 다른 말로 이를 클로저(Closure)라고 부릅니다. 아래 예제를 보시겠습니다. 아래 예제를 보시면 double_1 함수안에 double_2라는 함수를 선언하고 double_1 함수아서 사용하고 있습니다. 이럴 경우 해당 함수 내부에서만 사용할 수 있고 외부에서 접근하려고 하면 컴파일 에러가 발생합니다.

@Test
fun test2() {
    val double1 = double_1(x = 5, y = 2)

    println("값_1 = $double1") // 결과 : 값_1 = 100

    // double_2(x = 5, y = 2) 컴파일 에러
}

fun double_1(x: Int = 10, y: Int): Int {
    fun double_2(x: Int, y: Int) = x * y
    return x * y * double_2(x, y)
}

Trailling Coomma

함수를 아래와 같이 선언하였습니다. 일반적인 함수와 낯선 부분을 찾으실 수 있나요 ?

fun double_1(
        x: Int = 10,
        y: Int,
    ): Int {
        return x * y
    }

정답은 3번째 라인을 보시면 y: Int 이후 찍혀 있는 , 입니다. 위 코드에서는 추가적인 변수가 없음에도 불구하고 , 가 찍혀있습니다. 컴파일 에러는 나지 않으며 공식으로 코틀린에서 지원하는 문법입니다. 이를 Trailing Comma라고 부릅니다.

이렇게 사용했을 때 3가지의 장점을 코틀린 docs에서는 언급하고 있습니다.

  1. 소스 비교 명확히 가능 - git 등을 사용하여 코드를 비교할 때 , 는 변화로 잡지 않기 때문에 값의 변화에 집중할 수 있습니다.
  2. 순서 재정렬이 편함 - 함수, enum 등에서 재정렬할때 , 를 신경쓰지 않아도 됩니다.
  3. 코드 자동생성 만들 시 편함 - 마지막 파라미터일 때는 ,를 뺀다라는 로직이 필요없으므로 코드 자동생성을 만들때 좋습니다.

Trailing Comma는 반드시 사용해야하는것은 아닙니다. 위 글에서 사용에 매력을 느끼셨다면 사용하시는 프로젝트에 또는 팀에 한번 언급해보는건 어떨까요 ?

마무리

오늘은 이렇게 코틀린의 함수에 대해서 알아보는 시간을 가져보았습니다.

다음 시간에는 코틀린애서 클래스에 대해서 알아보는 시간을 가져보겠습니다.

감사합니다.

참조

코틀린 인 액션 (Kotlin In Action)

코틀린을 다루는 기술 (The Joy Of Kotlin)

kotlinlang_control-flow

댓글