코틀린
Do it! 코틀린 프로그래밍, 03-3 함수와 함수형 프로그래밍
조요피
2021. 8. 24. 23:15
고차 함수의 형태
고추 함수는 인자나 반환값으로 함수를 사용한다.
일반 함수를 인자나 반환값으로 사용하는 고차 함수
// 일반 함수를 인자로
fun main() {
val res1 = sum(3,2)
val res2 = mul(sum(3,3), 3)
}
fun sum(a: Int, b: Int) = a+b
fun mul(a: Int, b: Int) = a*b
// 일반 함수를 반환값으로
fun func(): Int {
return sum(2,2)
}
람다식을 인자나 반환값으로 사용하는 고차 함수
// 변수에 할당하는 람다식 함수 작성
var result: Int
val multi = {x: Int, y: Int -> x * y} // val multi: (Int, Int) -> Int = { x: Int, y: Int -> x * y }
result = multi(10, 20)
만약 함수 내용에 표현식이 2줄 이상이라면 마지막 표현식이 반환값이 된다.
val multi2: (Int, Int) -> Int = { x: Int, y: Int ->
x + y
x * y // 마지막 표현식이 반환
}
람다식의 매개변수에 자료형이 지정되어 있다면 변수의 자료형은 생략할 수 있다.
즉, 다음은 모두 같은 표현이다.
val multi: (Int, Int) -> Int = {x: Int, y: Int -> x * y}
val multi = {x: Int, y: Int -> x * y}
val multi = (Int, Int) -> Int = {x, y -> x * y}
val multi = {x, y -> x * y} // Error!
람다식의 자료형 생략
val greet = {println("Hello World")}
val square = {x: Int -> x * x}
val nestedLambda = {{println("nested")}}
매개변수에 람다식 함수를 이용한 고차 함수
fun main() {
val result: Int
result = highOrder({x, y -> x + y}, 10, 20)
println(result)
}
fun highOrder(sum: (Int, Int) -> Int, a: Int, b: Int): Int {
return sum(a,b)
}
인자와 반환값이 없는 람다식
val out: () -> Unit = {println("Hello World")}
out()
val new = out
new()
람다식과 고차 함수 호출하기
함수의 내용을 할당하거나 인자 혹은 반환값을 자유롭게 넘기려면 호출 방법을 이해해야 한다.
기본형 변수로 할당된 값은 스택에 있고 다른 함스에 인자로 전달하는 경우에는 해당 값이 복사되어 전달된다.
참조형 변수로 할당된 객체는 참조 주소가 스택에 있고 객체는 힙에 있다.
참조형 객체는 함수에 전달할 때는 참조된 주소가 복사되어 전달된다.
JVM에서 실행되는 자바나 코틀린은 함수를 호출할 때 인자의 값만 복사하는
'값에 의한 호출(Call by Value)'이 일반적이다.
C/C++에서 사용하는 포인터 주소 연산이 없기 때문에 주소 자체를 사용해 호출하는
'참조에 의한 호출(Call by Reference)'은 자바나 코틀린에서 사용되지 않는다.
자바는 객체가 전달될 때 주소 자 체를 전달하는 것이 아닌 값을 복사하는데
이 것은 참조에 의한 호출처럼 보이지만 그 값이 주소일 뿐.
코틀린은 람다식을 사용하면서 몇 가지 확장된 호출 방법을 사용할 수 있다.
값에 의한 호출
fun callByValue(b: Boolean): Boolean {
println("callByValue function")
return b
}
val lambda: () -> Boolean = {
println("lambda function")
true
}
fun main() {
val result = callByValue(lambda())
println(result)
}
//lambda function
//callByValue function
//true
이름에 의한 람다식 호출
fun callByName(b: () -> Boolean): Boolean {
println("callByName function")
return b()
}
val lambda: () -> Boolean = {
println("lambda function")
true
}
fun main() {
val result = callByName(lambda)
println(result)
}
//callByName function
//lambda function
//true
다른 함수의 참조에 의한 일반 함수 호출
fun sum(x: Int, y: Int) = x + y
funcParam(3, 2, sum) // Error! sum은 람다식이 아님
funcParam(3, 2, ::sum) // 2개의 콜론(::) 기호를 사용할 수 있다.
fun funcParam(a: Int, b: Int, c: (Int, Int) -> Int): Int {
return c(a,b)
}
람다식의 매개변수
람다식에 매개변수가 없는 경우
fun noParam(out: () -> String) = println(out())
noParam({"Hi"})
noParam {"Hi"} // 소괄호 생략 가능
람다식의 매개변수가 1개인 경우
fun oneParam(one: (String) -> String) = println(one("oneParam"))
// 모두 동일한 결과!
oneParam({ a -> "Hi $a"})
oneParam { a -> "Hi $a"} // 소괄호 생략 가능
oneParam { "Hi $it" } // it으로 대체 가능
람다식의 매개변수가 2개 이상인 경우
fun moreParam(out: (String, String) -> String) {
println(out("OneParam", "TwoParam"))
}
moreParam { a, b -> "HI! $a $b" }
moreParam { _, b -> "HI! $b" } // 첫 번째 문자열은 사용하지 않음
일반 매개변수와 람다식 매개변수를 같이 사용하기
fun withArgs(a: String, b: String, out: (String, String) -> String) {
println(out(a,b))
}
withArgs("A1", "A2", {a, b -> "Hi $a $b" })
withArgs("A1", "A2") {a, b -> "Hi $a $b" } // 마지막 인자가 람다식인 경우 소괄호 바깥으로 분리 가능