Kotlin에서 함수 만들기 및 사용하기

1. 시작하기 전에

이전 Codelab에서는 Hello, world!를 출력하는 간단한 프로그램을 알아봤습니다. 지금까지 작성한 프로그램에서는 두 가지 함수를 볼 수 있었습니다.

  • main() 함수: 모든 Kotlin 프로그램에 필요한 함수로, 프로그램의 진입점 또는 시작점입니다.
  • println() 함수: 텍스트를 출력하기 위해 main()에서 호출한 함수입니다.

이 Codelab에서는 함수에 관해 자세히 알아봅니다.

함수를 사용하면 main() 안에 모든 코드를 포함하는 대신 코드를 재사용 가능한 여러 개의 부분으로 나눌 수 있습니다. 함수는 Android 앱의 필수 구성요소이므로 함수를 정의하고 사용하는 방법을 아는 것은 Android 개발자가 되기 위한 중요한 단계입니다.

기본 요건

  • 변수, println() 함수, main() 함수를 비롯한 Kotlin 프로그래밍 기본 사항에 관한 지식

학습할 내용

  • 자체 함수를 정의하고 호출하는 방법
  • 변수에 저장할 수 있는 값을 함수에서 반환하는 방법
  • 여러 매개변수를 사용하여 함수를 정의하고 호출하는 방법
  • 이름이 지정된 인수를 사용하여 함수를 호출하는 방법
  • 함수 매개변수의 기본값을 설정하는 방법

필요한 항목

  • Kotlin 플레이그라운드에 액세스할 수 있는 웹브라우저

2. 함수 정의 및 호출하기

함수를 자세히 알아보기 전에 기본적인 용어 몇 가지를 살펴보겠습니다.

  • 함수를 선언(또는 정의)할 때는 fun 키워드를 사용하고, 작업 실행에 필요한 명령을 포함하는 코드를 중괄호로 묶습니다.
  • 함수를 호출하면 함수에 포함된 모든 코드가 실행됩니다.

지금까지는 모든 코드를 main() 함수 안에 작성했습니다. main() 함수는 실제로 코드의 어느 곳에서도 호출되지 않습니다. Kotlin 컴파일러가 이 함수를 시작점으로 사용합니다. main() 함수의 용도는 실행하려는 다른 코드(예: println() 함수 호출)를 포함하는 것뿐입니다.

println() 함수는 Kotlin 언어의 일부입니다. 이 외에도 자체 함수를 정의할 수 있습니다. 자체 함수를 정의하면 코드를 두 번 이상 호출해야 하는 경우 재사용할 수 있습니다. 다음 프로그램을 살펴보겠습니다.

fun main() {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}

main() 함수는 println() 문 두 개로 구성되어 있습니다. 하나는 로버의 생일을 축하는 문이고, 다른 하나는 로버의 나이를 명시하는 문입니다.

Kotlin에서는 모든 코드를 main() 함수 안에 포함하는 것이 가능하기는 하나, 그렇게 하는 것이 효율적이지 않은 경우가 있습니다. 예를 들어, 프로그램이 새해 인사도 포함하도록 하려면 main 함수는 새해 인사를 출력하는 println() 호출도 포함해야 합니다. 또는 친구 로버의 생일을 여러 번 축하하고 싶다면 똑같은 코드를 여러 번 복사하여 붙여넣거나 생일 축하를 출력하는 개별 함수를 만들면 됩니다. 여기서는 개별 함수를 만들어 보겠습니다. 특정 작업을 실행하는 개별 함수를 만들면 여러 가지 이점이 있습니다.

  • 재사용 가능한 코드: 두 번 이상 사용해야 하는 코드를 복사하여 붙여넣는 대신 필요할 때마다 함수를 호출하면 됩니다.
  • 가독성: 함수가 한 가지 특정 작업만 실행하도록 하면 다른 개발자와 팀원은 물론 향후 본인도 코드가 하는 작업을 정확히 파악할 수 있습니다.

다음 다이어그램에는 함수를 정의하는 문법이 나와 있습니다.

b44a09e0004280fe.png

함수 정의는 fun 키워드로 시작하고 함수 이름, 여는 괄호와 닫는 괄호, 여는 중괄호와 닫는 중괄호 순으로 이어집니다. 중괄호 안에는 함수 호출 시 실행될 코드가 포함됩니다.

여기서는 2개의 println() 문을 main() 함수 밖으로 가져오기 위한 새 함수를 만들어 보겠습니다.

  1. 브라우저에서 Kotlin 플레이그라운드를 열고 콘텐츠를 다음 코드로 바꿉니다.
fun main() {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}
  1. main() 함수 뒤에 birthdayGreeting()이라는 새 함수를 정의합니다. 이 함수는 main() 함수와 동일한 문법으로 선언합니다.
fun main() {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}

fun birthdayGreeting() {

}
  1. println() 문 두 개를 main()에서 birthdayGreeting() 함수의 중괄호 안으로 이동합니다.
fun main() {

}

fun birthdayGreeting() {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}
  1. main() 함수에서 birthdayGreeting() 함수를 호출합니다. 완성된 코드는 다음과 같습니다.
fun main() {
    birthdayGreeting()
}

fun birthdayGreeting() {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}
  1. 코드를 실행합니다. 다음과 같은 출력이 표시되어야 합니다.
Happy Birthday, Rover!
You are now 5 years old!

3. 함수에서 값 반환하기

보다 복잡한 앱에서는 함수가 텍스트를 출력하는 것보다 더 많은 일을 합니다.

Kotlin 함수는 반환 값이라는 데이터를 생성할 수 있습니다. 반환 값은 변수에 저장하여 코드의 다른 곳에서 사용할 수 있습니다.

함수를 정의할 때는 함수가 반환하도록 하려는 값의 데이터 유형을 지정할 수 있습니다. 반환 유형은 괄호 뒤에 콜론(:)을 입력하고 콜론 뒤에 유형 이름(Int, String 등)을 입력하여 지정합니다. 반환 유형 뒤와 여는 중괄호 앞에 공백 하나를 입력합니다. 함수 본문 내에서는 모든 문 뒤에서 return 문을 사용하여 함수가 반환하도록 할 값을 지정합니다. return 문은 return 키워드로 시작하고 그 뒤에 함수가 출력으로 반환하도록 할 값(변수 등)이 옵니다.

반환 유형을 사용하여 함수를 선언하는 문법은 다음과 같습니다.

268729385928f66f.png

Unit 유형

반환 유형을 지정하지 않은 경우 반환 유형은 기본적으로 Unit이 됩니다. Unit은 함수가 값을 반환하지 않음을 의미합니다. Unit은 다른 언어의 void 반환 유형과 동일합니다(예: Java 및 C의 void, Swift의 Void/빈 튜플 (), Python의 None). 값을 반환하지 않는 함수는 암시적으로 Unit을 반환합니다. 코드가 Unit을 반환하도록 수정하면 확인할 수 있습니다.

  1. birthdayGreeting() 함수 선언에서 닫는 괄호 뒤에 콜론을 추가하고 반환 유형을 Unit으로 명시합니다.
fun main() {
    birthdayGreeting()
}

fun birthdayGreeting(): Unit {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}
  1. 코드를 실행하고 모든 것이 정상적으로 작동하는지 살펴봅니다.
Happy Birthday, Rover!
You are now 5 years old!

Kotlin에서는 Unit 반환 유형을 지정하는 것이 선택 사항입니다. 아무것도 반환하지 않거나 Unit을 반환하는 함수의 경우 return 문이 필요하지 않습니다.

birthdayGreeting()에서 String 반환하기

이번에는 함수가 값을 어떻게 반환하는지 살펴보기 위해 birthdayGreeting() 함수가 단순히 결과를 출력하는 대신 문자열을 반환하도록 수정해 보겠습니다.

  1. Unit 반환 유형을 String으로 바꿉니다.
fun birthdayGreeting(): String {
    println("Happy Birthday, Rover!")
    println("You are now 5 years old!")
}
  1. 코드를 실행합니다. 오류가 발생합니다. 함수의 반환 유형을 선언할 경우(예: String) 이 함수는 return 문을 포함해야 합니다.
A 'return' expression required in a function with a block body ('{...}')
  1. 함수는 둘이 아닌 하나의 문자열만 반환할 수 있습니다. val 키워드를 사용하여 println() 문을 nameGreetingageGreeting, 2개의 변수로 바꿉니다. birthdayGreeting()에서 println() 호출을 삭제했으므로 birthdayGreeting()을 호출해도 아무것도 출력되지 않습니다.
fun birthdayGreeting(): String {
    val nameGreeting = "Happy Birthday, Rover!"
    val ageGreeting = "You are now 5 years old!"
}
  1. 이전 Codelab에서 배운 문자열 서식 지정 문법을 사용하여, 두 인사말로 구성된 함수가 하나의 문자열을 반환하도록 return 문을 추가합니다.

각각의 인사말을 개별 행에 출력하려면 \n 이스케이프 문자를 사용해야 합니다. 이는 이전 Codelab에서 배운 \" 이스케이프 문자와 같습니다. \n 문자가 줄바꿈으로 대체되어 두 인사말이 각각 별도의 행에 출력됩니다.

fun birthdayGreeting(): String {
    val nameGreeting = "Happy Birthday, Rover!"
    val ageGreeting = "You are now 5 years old!"
    return "$nameGreeting\n$ageGreeting"
}
  1. birthdayGreeting()이 값을 반환하므로 main()에서 결과를 문자열 변수에 저장할 수 있습니다. birthdayGreeting() 호출의 결과를 저장하도록 val을 사용하여 greeting 변수를 선언합니다.
fun main() {
    val greeting = birthdayGreeting()
}
  1. main()에서 println()을 호출하여 greeting 문자열을 출력합니다. 이제 main() 함수는 다음과 같습니다.
fun main() {
    val greeting = birthdayGreeting()
    println(greeting)
}
  1. 코드를 실행하고 결과가 전과 동일한지 관찰합니다. 이처럼 값을 반환하면 결과를 변수에 저장할 수 있습니다. 그렇다면 birthdayGreeting() 함수를 println() 함수 안에서 호출하면 어떻게 될까요?
Happy Birthday, Rover!
You are now 5 years old!
  1. 변수를 삭제하고 birthdayGreeting() 함수를 호출한 결과를 println() 함수에 전달합니다.
fun main() {
    println(birthdayGreeting())
}
  1. 코드를 실행하고 출력을 살펴봅니다. birthdayGreeting() 함수를 호출한 결과 반환되는 값이 println()에 곧바로 전달됩니다.
Happy Birthday, Rover!
You are now 5 years old!

4. birthdayGreeting() 함수에 매개변수 추가하기

앞에서 살펴보았듯이 println()을 호출할 때 괄호 안에 문자열을 포함하거나 함수에 값을 전달할 수 있습니다. birthdayGreeting() 함수로도 같은 작업을 할 수 있습니다. 하지만 먼저 birthdayGreeting()매개변수를 추가해야 합니다.

매개변수는 변수의 이름과 데이터 유형을 지정합니다. 그러면 변수를 다른 함수에 데이터로 전달하여 이 함수 내에서 액세스할 수 있습니다. 매개변수는 함수 이름 뒤에 오는 괄호 안에 선언됩니다.

9bf915c1980799ff.png

하나의 매개변수는 변수 이름과 데이터 유형으로 구성되며, 변수 이름과 데이터 유형은 콜론과 공백으로 구분됩니다. 여러 개의 매개변수는 쉼표로 구분됩니다.

현재 birthdayGreeting() 함수는 로버의 생일을 축하하는 용도로만 사용할 수 있습니다. 이번에는 birthdayGreeting() 함수에 원하는 이름을 전달하여 생일을 축하할 수 있도록 함수에 매개변수를 추가하겠습니다.

  1. birthdayGreeting() 함수의 괄호 안에서 name: String 문법을 사용하여 String 유형의 name 매개변수를 추가합니다.
fun birthdayGreeting(name: String): String {
    val nameGreeting = "Happy Birthday, Rover!"
    val ageGreeting = "You are now 5 years old!"
    return "$nameGreeting\n$ageGreeting"
}

앞 단계에서 정의한 매개변수는 val 키워드를 사용하여 선언한 변수처럼 작동합니다. 그 값은 birthdayGreeting() 함수의 어디서나 사용할 수 있습니다. 이전 Codelab에서는 변수의 값을 문자열에 삽입하는 방법을 배웠습니다.

  1. nameGreeting 문자열에서 Rover$ 기호 뒤에 name 매개변수가 오는 값으로 바꿉니다.
fun birthdayGreeting(name: String): String {
    val nameGreeting = "Happy Birthday, $name!"
    val ageGreeting = "You are now 5 years old!"
    return "$nameGreeting\n$ageGreeting"
}
  1. 코드를 실행하고 오류를 관찰합니다. 이제 name 매개변수를 선언했으므로 birthdayGreeting()을 호출할 때 String을 전달해야 합니다. 매개변수를 받는 함수를 호출할 때는 함수에 인수를 전달해야 합니다. 인수는 전달하는 값(예: "Rover")입니다.
No value passed for parameter 'name'
  1. "Rover"main()birthdayGreeting() 호출에 전달합니다.
fun main() {
    println(birthdayGreeting("Rover"))
}
  1. 코드를 실행하고 출력을 살펴봅니다. 여기서 이름 로버는 name 매개변수에서 가져온 것입니다.
Happy Birthday, Rover!
You are now 5 years old!
  1. birthdayGreeting()은 매개변수를 사용하므로 로버가 아닌 다른 이름으로 호출할 수 있습니다. println() 호출 내부에 birthdayGreeting() 호출을 하나 더 추가하고 "Rex" 인수를 전달합니다.
println(birthdayGreeting("Rover"))
println(birthdayGreeting("Rex"))
  1. 코드를 다시 실행한 후 birthdayGreeting()에 전달된 인수에 따라 출력이 달라지는 것을 관찰합니다.
Happy Birthday, Rover!
You are now 5 years old!
Happy Birthday, Rex!
You are now 5 years old!

5. 여러 매개변수를 갖는 함수

이름에 따라 인사말이 변경되도록 매개변수를 추가해 보았습니다. 그뿐 아니라 하나의 함수에 둘 이상의 매개변수를 정의할 수도 있고, 서로 다른 데이터 유형의 매개변수를 정의하는 것도 가능합니다. 이 섹션에서는 강아지의 나이에 따라서도 변경되도록 인사말을 수정해 보겠습니다.

565f16527e71f507.png

매개변수 정의는 쉼표로 구분합니다. 마찬가지로, 여러 개의 매개변수를 갖는 함수를 호출할 때는 전달된 인수를 쉼표로 구분합니다. 예를 보면서 살펴보겠습니다.

  1. name 매개변수 뒤에 Int 유형의 age 매개변수를 birthdayGreeting() 함수에 추가합니다. 새 함수 선언은 쉼표로 구분된 2개의 매개변수 nameage를 갖습니다.
fun birthdayGreeting(name: String, age: Int): String {
    val nameGreeting = "Happy Birthday, $name!"
    val ageGreeting = "You are now 5 years old!"
    return "$nameGreeting\n$ageGreeting"
}
  1. 새 인사말 문자열은 age 매개변수를 사용해야 합니다. ageGreeting 문자열에 age 매개변수의 값을 사용하도록 birthdayGreeting() 함수를 업데이트합니다.
fun birthdayGreeting(name: String, age: Int): String {
    val nameGreeting = "Happy Birthday, $name!"
    val ageGreeting = "You are now $age years old!"
    return "$nameGreeting\n$ageGreeting"
}
  1. 함수를 실행하고 출력의 오류를 살펴봅니다.
No value passed for parameter 'age'
No value passed for parameter 'age'
  1. main()에서 2개의 birthdayGreeting() 함수 호출이 강아지별로 서로 다른 나이를 전달하도록 수정합니다. 로버의 연령에는 5를 전달하고, 렉스의 연령에는 2를 전달합니다.
fun main() {
    println(birthdayGreeting("Rover", 5))
    println(birthdayGreeting("Rex", 2))
}
  1. 코드를 실행합니다. 두 매개변수의 값을 전달했으니 이제 함수를 호출하면 각 강아지의 이름과 나이가 반영된 문자열이 출력됩니다.
Happy Birthday, Rover!
You are now 5 years old!
Happy Birthday, Rex!
You are now 2 years old!

함수 서명

지금까지 함수 이름, 입력(매개변수)과 출력을 정의하는 방법을 알아보았습니다. 입력(매개변수)이 있는 함수 이름을 총칭하여 함수 서명이라고 합니다. 함수 서명은 반환 유형 앞의 모든 내용으로 구성되며 다음 코드 스니펫에 나와 있습니다.

fun birthdayGreeting(name: String, age: Int)

쉼표로 구분된 매개변수를 매개변수 목록이라고도 합니다.

이러한 용어는 다른 개발자들이 작성한 코드 문서에서 자주 보게 될 것입니다. 함수 서명은 함수의 이름과 전달할 수 있는 데이터 유형을 알려줍니다.

지금까지 함수 정의와 관련된 여러 가지 새로운 문법을 배웠습니다. 아래의 다이어그램에서 지금까지 알아본 함수 문법을 정리해 보세요.

51dad3b43e93abb4.png

6. 이름이 지정된 인수

앞에 나온 예시에서는 함수를 호출할 때 매개변수의 이름 name 또는 age를 지정할 필요가 없었습니다. 하지만 원하는 경우 매개변수의 이름을 지정할 수 있습니다. 예를 들어, 여러 개의 매개변수를 갖는 함수를 호출하거나 인수를 다른 순서로 전달하려는 경우(예: name 매개변수 앞에 age 매개변수를 지정하려는 경우) 매개변수의 이름을 지정할 수 있습니다. 함수를 호출할 때 매개변수 이름을 포함하면 이름이 지정된 인수라고 합니다. birthdayGreeting() 함수에서 이름이 지정된 인수를 사용해 보겠습니다.

  1. 다음 코드 스니펫에서 볼 수 있는 것처럼 이름이 지정된 인수를 사용하도록 Rex의 호출을 수정합니다. 먼저 매개변수의 이름을 입력하고 등호 기호를 입력한 다음 값을 입력합니다(예: name = "Rex").
println(birthdayGreeting(name = "Rex", age = 2))
  1. 코드를 실행하고 출력이 전과 동일한 것을 관찰합니다.
Happy Birthday, Rover!
You are now 5 years old!
Happy Birthday, Rex!
You are now 2 years old!
  1. 이름이 지정된 인수의 순서를 바꿉니다. 예를 들어, 이름이 지정된 인수 name 앞에 이름이 지정된 인수 age를 지정합니다.
println(birthdayGreeting(age = 2, name = "Rex"))
  1. 코드를 실행하고 출력이 전과 동일한 것을 관찰합니다. 인수의 순서를 변경했지만 동일한 매개변수에 동일한 값이 변경된 것을 알 수 있습니다.
Happy Birthday, Rover!
You are now 5 years old!
Happy Birthday, Rex!
You are now 2 years old!

7. 기본값 인수

함수 매개변수는 기본값 인수를 지정할 수도 있습니다. 로버가 가장 좋아하는 강아지인 경우, 또는 대부분의 경우에 특정 인수를 사용하여 함수를 호출하려는 경우 기본값 인수를 지정하면 됩니다. 함수를 호출할 때 기본값이 있는 인수는 생략할 수 있습니다. 생략하는 경우 기본값이 사용됩니다.

기본값 인수를 추가하려면 매개변수의 데이터 유형 뒤에 = 할당 연산자를 추가하고 원하는 값을 설정합니다. 기본 인수를 사용하도록 코드를 수정합니다.

  1. birthdayGreeting() 함수에서 name 매개변수를 기본값 "Rover"로 설정합니다.
fun birthdayGreeting(name: String = "Rover", age: Int): String {
    return "Happy Birthday, $name! You are now $age years old!"
}
  1. main()의 로버에 관한 첫 번째 birthdayGreeting() 호출에서 이름이 지정된 인수 age5로 설정합니다. age 매개변수는 name 뒤에 정의되어 있으므로 이름이 지정된 인수 age를 사용해야 합니다. 이름이 지정된 인수를 사용하지 않으면 Kotlin은 인수의 순서가 매개변수가 정의된 순서와 동일하다고 가정합니다. 이름이 지정된 인수는 Kotlin이 age 매개변수에 Int 값이 올 것을 예상하도록 하는 데 사용됩니다.
println(birthdayGreeting(age = 5))
println(birthdayGreeting("Rex", 2))
  1. 코드를 실행합니다. birthdayGreeting() 함수를 처음으로 호출하면 이름으로 '로버'를 출력합니다. 이름이 지정되지 않았기 때문입니다. 두 번째 birthdayGreeting() 호출은 name에 전달한 Rex 값을 여전히 사용합니다.
Happy Birthday, Rover! You are now 5 years old!
Happy Birthday, Rex! You are now 2 years old!
  1. 두 번째 birthdayGreeting() 함수 호출에서 이름을 삭제합니다. 다시 말하지만 name이 생략되었으므로 이름이 지정된 인수 age를 사용해야 합니다.
println(birthdayGreeting(age = 5))
println(birthdayGreeting(age = 2))
  1. 코드를 실행하고 두 번의 birthdayGreeting() 호출에서 모두 이름으로 '로버'가 출력되는 것을 관찰합니다. 이름이 지정된 인수가 전달되지 않았기 때문입니다.
Happy Birthday, Rover! You are now 5 years old!
Happy Birthday, Rover! You are now 2 years old!

8. 결론

축하합니다. Kotlin에서 함수를 정의하고 호출하는 방법을 배웠습니다.

요약

  • 함수는 fun 키워드를 사용하여 정의되며, 재사용 가능한 코드를 포함합니다.
  • 함수는 대규모 프로그램을 쉽게 유지 관리할 수 있도록 도와주며, 코드의 불필요한 반복을 방지합니다.
  • 함수는 값을 반환할 수 있으며, 반환된 값은 변수에 저장하여 나중에 사용할 수 있습니다.
  • 함수는 매개변수를 받을 수 있습니다. 매개변수는 함수 본문 안에서 사용할 수 있는 변수입니다.
  • 인수는 사용자가 함수를 호출할 때 전달하는 값입니다.
  • 함수를 호출할 때 인수에 이름을 지정할 수 있습니다. 이름이 지정된 인수를 사용하면 출력에 영향을 주지 않으면서 인수의 순서를 바꿀 수 있습니다.
  • 기본값 인수를 지정하면 함수를 호출할 때 인수를 생략할 수 있습니다.