학습할 내용

  • 람다 문법으로 함수를 정의하는 방법
  • 변수에 함수를 저장하는 방법
  • 함수를 다른 함수에 인수로 전달하는 방법
  • 다른 함수에서 함수를 반환하는 방법
  • null을 허용하는 함수 유형을 사용하는 방법
  • 람다 표현식을 더 간결하게 만드는 방법
  • 고차 함수의 정의
  • repeat() 함수 사용 방법

변수에 함수 저장

Kotlin 플레이그라운드로 이동합니다.

main() 함수 다음에 trick() 함수를 정의합니다.

fun main() {

}

fun trick() {
    println("No treats!")
}

main() 함수의 본문에서 trickFunction이라는 변수를 만들고 trick과 같게 설정합니다. 함수를 변수에 저장하려 하기 때문에 괄호를 사용하지 않습니다.

fun main() {
    val trickFunction = trick
}

fun trick() {
    println("No treats!")
}

코드를 실행합니다.

Kotlin 컴파일러에서 tricktrick() 함수의 이름으로 인식하지만 변수에 함수가 할당되는 대신 함수가 호출될 것으로 예상하기 때문에 오류가 발생합니다.

Function invocation 'trick()' expected.

함수를 값으로 참조하려면 함수 참조 연산자(::)를 사용해야 합니다.

fun main() {
    val trickFunction = ::trick
}

fun trick() {
    println("No treats!")
}

람다 표현식을 사용하여 함수 재정의

람다 표현식은 fun 키워드 없이 함수를 정의할 수 있는 간결한 문법입니다. 람다 표현식은 다른 함수에 관한 함수 참조 없이 변수에 직접 저장할 수 있습니다.

val 변수이름 = {
    함수 본문
}

람다 표현식을 사용하여 trick() 함수를 다시 작성합니다.

fun main() {
    val trickFunction = ::trick
}

val trick = {
    println("No treats!")
}

main() 함수에서 함수 참조 연산자(::)를 삭제합니다.

fun main() {
    val trickFunction = trick
}

val trick = {
    println("No treats!")
}

main() 함수에서 trick() 함수를 호출합니다.

fun main() {
    val trickFunction = trick
    trick()
}

val trick = {
    println("No treats!")
}

코드를 실행합니다.

No treats!

main() 함수에서 trickFunction 변수를 함수인 것처럼 호출합니다.

fun main() {
    val trickFunction = trick
    trick()
    trickFunction()
}

val trick = {
    println("No treats!")
}

코드를 실행합니다.

No treats!
No treats!

람다 표현식을 사용하면 함수를 저장할 변수를 만들고, 이러한 변수를 함수처럼 호출하고, 그것을 다른 변수에 저장하여 함수처럼 호출할 수 있습니다.

함수를 데이터 유형으로 사용

Kotlin에 유형 추론이 있다고 배웠습니다. 이전 예에서는 Kotlin 컴파일러가 trick의 값이 함수임을 추론할 수 있었습니다. 그러나 함수 매개변수의 유형이나 반환 유형을 지정하려면 함수 유형을 표현하기 위한 문법을 알아야 합니다.

(parameters) -> return type

앞서 선언한 trick 변수의 데이터 유형은 () -> Unit입니다. 함수에 매개변수가 없으므로 괄호가 비어 있습니다. 그리고 함수에서 아무것도 반환하지 않으므로 반환 유형은 Unit입니다.

trick 변수 다음에 treat이라는 변수를 선언합니다.

fun main() {
    val trickFunction = trick
    trick()
    trickFunction()
}

val trick = {
    println("No treats!")
}

val treat = {
    println("Have a treat!")
}

treat 변수의 데이터 유형을 () -> Unit으로 지정합니다.

fun main() {
    val trickFunction = trick
    trick()
    trickFunction()
}

val trick = {
    println("No treats!")
}

val treat: () -> Unit = {
    println("Have a treat!")
}

main() 함수에서 treat() 함수를 호출합니다.

fun main() {
    val trickFunction = trick
    trick()
    trickFunction()
    treat()
}

val trick = {
    println("No treats!")
}

val treat: () -> Unit = {
    println("Have a treat!")
}

코드를 실행합니다. treat 변수만 데이터 유형을 명시적으로 선언하더라도 두 변수의 데이터 유형은 동일합니다.

No treats!
No treats!
Have a treat!

함수를 반환 유형으로 사용

함수가 데이터 유형이므로 다른 데이터 유형처럼 함수를 사용할 수 있습니다. 다른 함수에서 함수를 반환할 수 있습니다.

fun functionName(): functionType {
    //code
    return NameOfAnotherFunction
}

main() 함수 본문 코드를 삭제합니다. main() 함수 다음에 Boolean 유형의 isTrick 매개변수를 허용하는 trickOrTreat() 함수를 정의합니다.

fun main() {
    
}

fun trickOrTreat(isTrick: Boolean): () -> Unit {

}

val trick = {
    println("No treats!")
}

val treat: () -> Unit = {
    println("Have a treat!")
}

trickOrTreat() 함수의 본문에서 isTricktrue이면 trick() 함수를 반환하고, false이면 treat() 함수를 반환하는 if 문을 추가합니다.

fun main() {
    
}

fun trickOrTreat(isTrick: Boolean): () -> Unit {
    if (isTrick) {
        return trick
    } else {
        return treat
    }
}

val trick = {
    println("No treats!")
}

val treat: () -> Unit = {
    println("Have a treat!")
}

main() 함수에서 treatFunction이라는 변수를 만들어 trickOrTreat() 호출 결과에 할당한 다음 isTrick 매개변수에 false를 전달합니다. 그런 다음 trickFunction이라는 변수를 만들어 trickOrTreat() 호출 결과에 할당한 다음 isTrick 매개변수에 true를 전달합니다. 그다음 줄에서 두 함수를 호출합니다.

fun main() {
    val treatFunction = trickOrTreat(false)
    val trickFunction = trickOrTreat(true)
    treatFunction()
    trickFunction()
}

fun trickOrTreat(isTrick: Boolean): () -> Unit {
    if (isTrick) {
        return trick
    } else {
        return treat
    }
}

val trick = {
    println("No treats!")
}

val treat: () -> Unit = {
    println("Have a treat!")
}

코드를 실행합니다.

Have a treat!
No treats!

함수를 다른 함수에 인수로 전달

함수 유형을 선언할 때 매개변수에는 라벨이 지정되지 않습니다. 각 매개변수의 데이터 유형을 쉼표로 구분하여 지정하기만 하면 됩니다.

(String, Int) -> Int

매개변수를 취하는 함수를 람다 표현식으로 작성할 때 매개변수의 순서대로 이름이 지정됩니다. 매개변수 이름은 여는 중괄호 다음에 나열되고 쉼표로 구분됩니다. ->는 함수 본문에서 매개변수 이름을 구분합니다.

val functionName = { parameter01, parameter02 ->
    functionBody
}

함수를 매개변수로 사용하도록 trickOrTreat() 함수를 업데이트 합니다. isTrick 매개변수 다음에 (Int) -> String 유형의 extraTreat 매개변수를 추가합니다.

fun main() {
    val treatFunction = trickOrTreat(false)
    val trickFunction = trickOrTreat(true)
    treatFunction()
    trickFunction()
}

fun trickOrTreat(isTrick: Boolean, extraTreat: (Int) -> String): () -> Unit {
    if (isTrick) {
        return trick
    } else {
        return treat
    }
}

val trick = {
    println("No treats!")
}

val treat: () -> Unit = {
    println("Have a treat!")
}

else 블록의 return 문 앞에서 println()을 호출하고 extraTreat() 함수 호출을 전달합니다. 5extraTreat() 호출에 전달합니다.

fun trickOrTreat(isTrick: Boolean, extraTreat: (Int) -> String): () -> Unit {
    if (isTrick) {
        return trick
    } else {
        println(extraTreat(5))
        return treat
    }
}

trickOrTreat() 함수를 호출하기 전에 main() 함수에서 coins() 함수를 추가합니다. coins() 함수는 Int 매개변수의 이름을 quantity로 지정하고 String을 반환합니다.

fun main() {
    val coins: (Int) -> String = { quantity ->
        "$quantity quaters"
    }
    val treatFunction = trickOrTreat(false)
    val trickFunction = trickOrTreat(true)
    treatFunction()
    trickFunction()
}

람다 표현식에 사용할 수 없는 return 키워드가 없음을 알 수 있습니다. 대신 함수의 마지막 표현식 결과가 반환 값이 됩니다.

coins() 함수 다음에 cupcake() 함수를 추가합니다.

fun main() {
    val coins: (Int) -> String = { quantity ->
        "$quantity quaters"
    }
    val cupcake: (Int) -> String = {
        "Have a cupcake!"
    }
    val treatFunction = trickOrTreat(false)
    val trickFunction = trickOrTreat(true)
    treatFunction()
    trickFunction()
}

trickOrTreat() 함수 호출을 업데이트합니다.

fun main() {
    val coins: (Int) -> String = { quantity ->
        "$quantity quaters"
    }
    val cupcake: (Int) -> String = {
        "Have a cupcake!"
    }
    val treatFunction = trickOrTreat(false, coins)
    val trickFunction = trickOrTreat(true, cupcake)
    treatFunction()
    trickFunction()
}

코드를 실행합니다.

5 quaters
Have a treat!
No treats!

null을 허용하는 함수 유형

다른 데이터 유형과 마찬가지로 함수 유형도 null을 허용하도록 선언할 수 있습니다. 함수를 null을 허용하도록 선언하려면 함수 유형을 괄호로 묶은 다음 닫는 괄호 밖에 ? 기호를 추가합니다. 예를 들어 () -> String 유형을 null을 허용하게 하려면 (() -> String)? 유형으로 선언하면 됩니다.

trickOrTreat() 함수를 호출할 때마다 extraTreat() 함수를 제공할 필요가 없도록 extraTreat 매개변수에서 null을 허용하도록 설정합니다.

extraTreat 매개변수의 유형을 (() -> String)? 유형으로 변경합니다.

fun trickOrTreat(isTrick: Boolean, extraTreat: ((Int) -> String)?): () -> Unit {
    if (isTrick) {
        return trick
    } else {
        println(extraTreat(5))
        return treat
    }
}

null이 아닌 경우에만 if 문을 사용하여 함수를 호출하도록 extraTreat() 함수 호출을 수정합니다.

fun trickOrTreat(isTrick: Boolean, extraTreat: ((Int) -> String)?): () -> Unit {
    if (isTrick) {
        return trick
    } else {
        if (extraTreat != null) {
            println(extraTreat(5))
        }
        return treat
    }
}

cupcake() 함수를 삭제하고, trickOrTreat() 함수의 두 번째 호출에서 cupcake 인수를 null로 바꿉니다.

fun main() {
    val coins: (Int) -> String = { quantity ->
        "$quantity quaters"
    }
    
    val treatFunction = trickOrTreat(false, coins)
    val trickFunction = trickOrTreat(true, null)
    treatFunction()
    trickFunction()
}

코드를 실행합니다. 출력은 달라지지 않습니다.

5 quaters
Have a treat!
No treats!

약식 문법으로 람다 표현식 작성

매개변수 이름 생략

함수에 매개변수가 한 개 있고 이름을 지정하지 않는 경우 Kotlin은 암시적으로 매개변수에 it 이름을 할당합니다. 그러므로 매개변수 이름과 -> 기호를 생략할 수 있게 되고 람다 표현식이 더 간결해집니다.

val coins: (Int) -> String = { quantity ->
    "$quantity quarters"
}
val coins: (Int) -> String = {
    "$it quarters"
}

위와 같이 매개변수에 약식 문법을 사용하도록 coins() 함수를 업데이트 합니다.

람다 표현식을 함수에 직접 전달

람다 표현식이 trickOrTreat() 함수 호출에 직접 전달되도록 람다 표현식을 이동합니다.

fun main() {
    val coins: (Int) -> String = {
        "$it quaters"
    }
    
    val treatFunction = trickOrTreat(false, { "$it quaters" })
    val trickFunction = trickOrTreat(true, null)
    treatFunction()
    trickFunction()
}

coins 변수는 더 이상 사용되지 않으므로 삭제합니다.

fun main() {
    val treatFunction = trickOrTreat(false, { "$it quaters" })
    val trickFunction = trickOrTreat(true, null)
    treatFunction()
    trickFunction()
}

후행 람다 문법 사용

함수 유형이 함수의 마지막 매개변수인 경우 닫는 괄호 다음에 람다 표현식을 배치하여 함수를 호출할 수 있습니다.

trickOrTreat(false, 람다표현식)
trickOrTreat(fase) 람다표현식

이렇게 하면 람다 표현식이 다른 매개변수와 구분되므로 코드를 더 쉽게 읽을 수 있습니다.

treatFunction 변수에서 람다 표현식을 후행 람다 문법으로 변경합니다.

fun main() {
    val treatFunction = trickOrTreat(false) { "$it quaters" }
    val trickFunction = trickOrTreat(true, null)
    treatFunction()
    trickFunction()
}

repeat() 함수 사용

함수가 함수를 반환하거나 함수를 인수로 취하는 경우 이를 고차 함수라고 합니다. trickOrTreat() 함수가 ((Int) -> String)? 유형의 함수를 매개변수로 취하고 () -> Unit 유형의 함수를 반환하므로 고차 함수입니다.

repeat() 함수도 고차 함수 중 하나입니다. repeat() 함수는 함수로 for 루프를 표현할 수 있는 간결한 방법입니다.

repeat(times: Int, action: (Int) -> Unit)

times 매개변수는 동작이 발생해야 하는 횟수입니다. action 함수의 Int 매개변수는 동작이 지금까지 실행된 횟수입니다.

repeat() 함수가 어떻게 작동하는지 확인하기 위해 코드를 업데이트합니다.

repeat() 함수를 호출합니다. times 매개변수에 4를 전달하고 action 함수에 후행 람다 문법을 사용합니다. 람다 표현식의 Int 매개변수에 이름을 지정할 필요는 없습니다.

fun main() {
    val treatFunction = trickOrTreat(false) { "$it quarters" }
    val trickFunction = trickOrTreat(true, null)
    repeat(4) {
        treatFunction()
    }
    trickFunction()
}

코드를 실행합니다.

5 quarters
Have a treat!
Have a treat!
Have a treat!
Have a treat!
No treats!

정리

  • Kotlin의 함수는 데이터 유형처럼 처리할 수 있습니다.
  • 람다 표현식은 함수를 작성하는 약식 문법을 제공합니다.
  • 함수 유형을 다른 함수에 전달할 수 있습니다.
  • 다른 함수에서 함수 유형을 반환할 수 있습니다.
  • 람다 표현식은 마지막 표현식의 값을 반환합니다.
  • 매개변수 하나가 포함된 람다 표현식에서 매개변수 라벨이 생략된 경우 람다 표현식은 it 식별자로 참조됩니다.
  • 람다는 변수 이름 없이 인라인으로 작성할 수 있습니다.
  • 함수의 마지막 매개변수가 함수 유형인 경우 후행 람다 문법을 사용하여 함수를 호출할 때 람다 표현식을 후행 괄호 다음으로 이동할 수 있습니다.
  • 고차 함수는 다른 함수를 매개변수로 사용하거나 함수를 반환하는 함수입니다.
  • repeat() 함수는 for 루프와 비슷하게 작동하는 고차 함수입니다.

📚 참고: Android Developers 공식 Kotlin 학습 자료 본 글은 Android Developers의 Kotlin 교육 콘텐츠를 참고하여 재구성했습니다.

카테고리:

업데이트:

댓글남기기