깨알 개념/Kotlin

[Kotlin] 함수 타입(Fuction types) 표현식

interfacer_han 2024. 1. 31. 10:17

#1 코틀린의 함수는 일급 객체다

 

일급 객체 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 컴퓨터 프로그래밍 언어 디자인에서, 일급 객체(영어: first-class object)란 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 가리킨다. 보통

ko.wikipedia.org

코틀린에서는 함수를 일급 객체(First-class object)로 취급한다. 코틀린에서 함수를 일급 객체로 취급한다는 것은 함수가 다른 객체들과 동등하게 다루어지고, 다양한 연산을 적용할 수 있다는 의미를 갖는다. 그렇다면, 함수의 데이터 타입 또한 존재할 것이다. val s : String에서 s는 데이터 타입이 String인 객체인 것처럼, 이 String의 역할을 하는 함수 버전 타입 말이다.

 

#2 함수 타입 표현식의 문법

#2-1 기본 문법

fun myFunction(value1: Int, value2: Int): Int {
    return value1 * value2 + 8
}

fun main() {
    val functionReference: (Int, Int) -> Int

    // 더블콜론(::)은 코틀린에서 함수, 클래스, 멤버 함수, 생성자 등을 참조하는 데에 사용하는 기호
    functionReference = ::myFunction 

    println(functionReference(7, 9)) // 출력 결과: 71
}

함수 타입(Function types) 표현식(매개변수'들') -> 리턴 타입의 형태로 함수의 input과 output를 기술한다. 예를 들어 val f : (Int, Int) -> Int에서 f는 매개변수로 Int, String을 받고 return 타입은 Int인 함수다. 만약 위 코드에서 functionReference의 함수 타입 표현식이 myFunction과 달랐다면 myFunction을 참조할 수 없었을 것이다.

 

#2-2 매개변수가 없는 경우

val functionReference: () -> Int

매개변수가 없다면 ()와 같이 함수 타입 표현식의 괄호 안에 아무것도 넣지 않으면 된다.

 

#2-3 return을 하지 않는 경우

val functionReference: (Int, Int) -> Unit

함수 타입 표현식에서 함수의 return이 없는 경우 return 타입 자리에 Unit을 넣는다. Unit은 자바의 void에 대응되는 키워드다.

 

#2-4 매개변수도 없고 return도 하지 않는 경우

val functionReference: () -> Unit

매개변수도 없고, return도 없다면 해당 함수는 () -> Unit 타입이다.

 

#1에서 코틀린에서 함수를 일급 객체로 취급한다는 것은 함수가 다른 객체들과 동등하게 다루어지고, 다양한 연산을 적용할 수 있다는 의미를 갖는다고 했었다. 다음으론 함수를 다른 객체들과 동등하게 다룰 때 행해지는 다양한 연산의 예이다.

 

#3 함수 객체 연산

#3-1 함수를 변수에 할당할 수 있음

val functionReference: (Int) -> Int = fun(args: Int): Int {
    return args + 1
}

fun main() {
    val result = functionReference(2)
    println(result) // 출력 결과: 3
}

/* 위 코드와 같은 동작을 하는 람다식 버전 코드
val functionReference: (Int) -> Int = { args -> args + 1 }

fun main() {
    val result = functionReference(2)
    println(result)
}
*/

#2-1의 코드에서처럼 변수에 함수를 할당할 수 있다. 코틀린에서 어떤 함수를 익명 함수로 쓰면서 해당 함수에 이름을 붙이면 에러(Anonymous functions with names are prohibited)가 나므로 fun 키워드 오른쪽에 함수 이름을 쓰지 않았다.

 

#3-2 함수를 return할 수 있음

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

fun getAddFunction(): (Int, Int) -> Int {
    return ::add
}

fun main() {
    val submit = getAddFunction()(2, 3)
    println(submit) // 출력 결과: 5
}

getAddFunction()의 return 타입은 Int형 2개를 받아 Int를 리턴하는 '함수'다.

 

#3-3 함수를 인자로 전달 가능

fun calculateNumbers(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
    return operation(x, y)
}

fun main() {
    val result = calculateNumbers(4, 5, fun(args1, args2): Int { return args1 * args2 })
    println(result) // 출력 결과: 20
}

/* 위 코드와 같은 동작을 하는 람다식 버전 코드
fun calculateNumbers(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
    return operation(x, y)
}

fun main() {
    val result = calculateNumbers(4, 5) { args1, args2 -> args1 * args2 }
    println(result)
}
*/

#3-1에서와 마찬가지로, 인자로 전달되는 익명 함수의 이름을 뺐다.

 

#4 요약

함수를 일반 데이터 객체처럼 다룰 수 있다면, 당연히 함수의 '데이터 타입' 또한 존재해야 한다.