[kotlin] 고차 함수(High-Order Function)
고차 함수(High-Order Function)란, 매개변수로 함수를 전달받거나 함수를 반환하는 함수를 말한다.
fun hoFun(argFun: (Int) -> Int){
val result = argFun(10)
println("result: $result")
}
hoFun({x -> x * x})
hoFun {x -> x * x} // () 생략가능
val array = arrayOf(10, 20, 15, 22, 8)
array.filter{ x -> x > 10 }
.forEach{ x -> println(x) }
// 함수 타입 매개변수가 여러 개일 때 - 마지막 인수만 () 생략가능
fun hoFun1(no: Int, argFun1: (Int) -> Int, argFun2: (Int) -> Boolean){
}
hoFun1(10, {it * it}) {it > 10}
// 함수 타입 기본값 이용
fun hoFun2(
x1: Int,
argFun1: (Int) -> Int,
argFun2: (Int) -> Boolean = {x: Int -> x > 10}
){
val result = argFun1(x1)
println("result ${argFun2(result)}")
}
hoFun2(2, {x: Int -> x * x}, {x: Int -> x > 20})
hoFun2(4, {x: Int -> x * x})
// 함수 반환
fun hoFun3(str: String): (x1: Int, x2: Int) -> Int {
when(str){
"-" -> return {x1, x2 -> x1 - x2}
"*" -> return {x1, x2 -> x1 * x2}
"/" -> return {x1, x2 -> x1 / x2}
else -> return {x1, x2 -> x1 + x2}
}
}
val resultFun = hoFun3("*")
println("result * : ${resultFun(10, 5)}")
일반적으로 고차 함수에서 매개변수나 반환값으로 람다 함수를 많이 이용하지만, 함수 참조나 익명 함수를 이용해도 된다.
// 참조 함수 이용
fun hoFun1(argFun: (x: Int) -> Int) {
println("$argFun(10)}")
}
fun nameFun(x: Int): Int {
return x * 5
}
hoFun1(::nameFun)
// 익명 함수 이용 - return 명시하고 싶을 때
val anonyFun1 = fun(x: Int): Int = x * 10
val anonyFun2 = fun(x: Int): Int {
println("I am anonymous function")
return x * 10
}
fun hoFun2(argFun: (Int) -> Int){
println("${argFun(10)}")
}
hoFun2(fun(x: Int): Int = x * 10)
코틀린 API의 유용한 고차 함수
run()
람다 함수를 실행하고 그 결과값을 얻는 목적으로 사용, 객체의 멤버에 접근하기 위해 사용
// inline fun <R> run(block: () -> R):R
// inline fun <T, R> T.run(block: T.() -> R):R
// 실행 후 결과값 바로 얻기
val result = run {
println("lambdas function call...")
10 + 20
}
println("result : $result")
// user.name = "son" 대신 name = "son" 으로 접근가능
val runResult = user.run {
name = "kim"
age = 28
sayHello()
sayInfo()
10 + 20
}
println("result : $runResult")
apply()
run() 함수와 사용 목적은 같으나 반환하는 값에 차이가 있다. run() 함수는 람다 함수의 반환값을 그대로 반환하지만, apply() 함수는 apply() 함수를 적용한 객체를 반환한다.
// inline fun <T> T.apply(block: T.() -> Unit):T
// 같은 객체 반환. 즉, user2 === user ===는 객체 동일성(주소), ==는 값 비교 (equals)
val user2 = user.apply {
name = "park"
sayHello()
sayInfo()
}
println("user name : ${user.name}, user2 name : ${user2.name}") // park
user.name = "aaa"
user2.name = "bbb"
println("user name : ${user.name}, user2 name : ${user2.name}") // bbb
let()
let() 함수는 자신을 호출한 객체를 매개변수로 전달받은 람다 함수에 매개변수로 전달하는 함수이다. 그리고 람다 함수의 반환값을 let() 함수의 반환값으로 그대로 전달해준다.
// inline fun <T, R> T.let(block: (T) -> R):R
val result = User("kim", 28).let { user ->
letTestFun(user)
30 + 20
}
User("kim", 28).let {
letTestFun(it)
}
let() 함수를 호출하면 해당 객체가 let() 함수에 지정된 람다 함수의 매개변수에 대입되고, 람다 함수에서 해당 객체를 이용할 수 있다. 짧게 이용하기 위한 변수 선언을 줄이고자 할 때 사용하면 된다.
with()
with() 함수는 run() 함수와 사용 목적이 유사하다. 한 객체의 멤버에 반복해서 접근할 때 객체명을 일일이 명시하지 않고 멤버에 바로 접근하려는 용도. run() 함수와의 차이점은 run() 함수는 자신을 호출한 객체를 이용하지만, with() 함수는 매개변수로 지정한 객체를 이용한다.
// inline fun <T, R> with(receiver: T, block: T.() -> R):R
user.run{
name = "son"
sayHello()
}
with(user){
name = "son"
sayHello()
}