[android : kotlin] 코틀린 람다식(Lambda Expression) 사용 방법
람다식(Lambda Expression)이란? 이름이 없어도 함수 역할을 하는 익명 함수의 하나의 형태이다. 람다식은 화살표 표기법을 사용한다. 람다식은 고차 함수에서 인자로 넘기거나 결과값으로 반환 등을 할 수 있다.
■람다식의 예
//이름이 없는 함수 형태이다.
{ x , y -> x + y }
val multi = {x: Int, y:Int -> x * y}
println(multi(10,20)
val multi2: (Int, Int) -> Int = {x: Int, y:Int ->
println("x*y")
x*y // 마지막 표현식이 반횐됨.
}
■람다식의 구성
■자료형의 생략
//생략되지 않은 전체 표현
val multi: (Int, Int) -> Int = {x:Int, y:Imt -> x * y}
// 선언 자료형 생략
val mulit = {x:Int, y:Int -> x * y}
//람다식 매개변수 자료형의 생략
val multi: (Int, Int) -> Int = {x, y -> x * y}
//에러!! 추론 불가
val multi: {X,y -> x *y}
■람다식 안에 람다식이 있는 경우
val nestedLambda: ()->()->Unit = { { println("nested") } }
■반환값이 없거나 매개변수가 하나만 있을 경우
val greet: ()->Unit
val square: (Int)->Int = { x -> x * X }
fun main() {
var result: Int
// 람다식을 매개변수와 인자로 사용한 함수
result = highOrder({ x, y -> x + y}, 10, 20)
println(result)
result = highOrder({ x, y -> x * y}, 10, 20)
println(result)
result = highOrder({ x, y -> x - y}, 10, 20)
println(result)
// 반환값이 없는 람다식의 선언
val out: () -> Unit = { println("Hello World!") }
// 추론이 가능하므로 val out = { println("Hello World!") }와 같이 생략 가능
// 람다식이 들어있는 변수를 다른 변수에 할당
out() // 함수처럼 사용가능
}
fun highOrder(caluate: (Int, Int) -> Int, a: Int, b: Int): Int {
return caluate(a, b)
}
[출력결과]
30
200
-10
Hello World!
■값에 의한 호출(CallByValue) : 함수가 인자로 전달될 경우 – 람다식 함수는 값으로 처리되어, 그 즉시 함수가 수행된 후 값을 전달
fun main() {
val result = callByValue(lambda()) // 람다식 함수를 호출
println(result)
}
fun callByValue(b: Boolean): Boolean { // 일반 변수 자료형으로 선언된 매개변수
println("callByValue function")
return b
}
val lambda: () -> Boolean = { // 람다 표현식이 두 줄이다
println("lambda function")
true // 마지막 표현식 문장의 결과가 반환
}
[출력결과]
lambda function
callByValue function
true
■이름에 의한 호출(CallByName)
fun main() {
val result2 = callByName(otherLambda) // 람다식 이름으로 호출
println(result2)
}
fun callByName(b: () -> Boolean): Boolean { // 람다식 함수 자료형으로 선언된 매개변수
println("callByName function")
return b()
}
val otherLambda: () -> Boolean = {
println("otherLambda function")
true
}
[출력결과]
callByName function
otherLambda function
true
■다른 함수의 참조에 의한 호출
fun main() {
// 1. 인자와 반환값이 있는 함수
val res1 = funcParam(3, 2, sum)
println(res1)
// 2. 인자가 없는 함수
hello(::text) // 반환값이 없음
// 3. 일반 변수에 값처럼 할당
val likeLambda = ::sum
println(likeLambda(6,6))
}
fun sum(a: Int, b: Int) = a + b
fun text(a: String, b: String) = "Hi! $a $b"
fun funcParam(a: Int, b: Int, c: (Int, Int) -> Int): Int {
return c(a, b)
}
fun hello(body: (String, String) -> String): Unit {
println(body("Hello", "World"))
}
[출력결과] sum은 람다식이 아님으로 오류가 발생된다. sum을 람다식 처럼 호출하기 위해 콜론(::)를 사용하여 참조방식으로 호출한다.
No value passed for parameter 'a'
No value passed for parameter 'b'
Function invocation 'sum(...)' expected
Type mismatch: inferred type is Int but (Int, Int) -> Int was expected
[출력 결과] ::sum으로 호출한 경우
5
Hi! Hello World
12
■매개변수가 없는 경우
fun main() {
// 매개변수 없는 람다식 함수
noParam({ "Hello World!" })
noParam { "Hello World!!!!" } // 위와 동일 결과, 소괄호 생략 가능
}
// 매개변수가 없는 람다식 함수가 noParam 함수의 매개변수 out으로 지정됨
fun noParam(out: () -> String) = println(out())
[출력결과]
Hello World!
Hello World!!!!
■매개변수가 1개 있는 경우
fun main() {
// 매개변수가 하나 있는 람다식 함수
oneParam({ a -> "Hello World! $a" })
oneParam { a -> "Hello World!! $a" } // 위와 동일 결과, 소괄호 생략 가능
oneParam { "Hello World!!! $it" } // 위와 동일 결과, it으로 대체 가능
}
// 매개변수가 하나 있는 람다식 함수가 oneParam함수의 매개변수 out으로 지정됨
fun oneParam(out: (String) -> String) {
println(out("OneParam"))
}
[출력결과]
Hello World! OneParam
Hello World!! OneParam
Hello World!!! OneParam
■매개변수가 여러개 있는 경우
fun main() {
// 매개변수가 두 개 있는 람다식 함수
moreParam { a, b -> "Hello World! $a $b"} // 매개변수명 생략 불가
}
// 매개변수가 두 개 있는 람다식 함수가 moreParam 함수의 매개변수로 지정됨
fun moreParam(out: (String, String) -> String) {
println(out("OneParam", "TwoParam"))
}
[출력결과]
Hello World! OneParam TwoParam
■매개변수를 생략하는 경우 : 언더바(_)를 사용하여 생략한다.
moreParam { _, b -> "Hello World! $b"} // 첫 번째 문자열은 사용하지 않고 생략
■일반 매개변수와 람다식 매개변수를 같이 사용하는 경우
fun main() {
// 인자와 함께 사용하는 경우
withArgs("Arg1", "Arg2", { a, b -> "Hello World! $a $b" }) // ①
// withArgs()의 마지막 인자가 람다식인 경우 소괄호 바깥으로 분리 가능
withArgs("Arg1", "Arg2") { a, b -> "Hello World!!! $a $b" } // ②
}
// withArgs함수는 일반 매개변수 2개를 포함, 람다식 함수를 마지막 매개변수로 가짐
fun withArgs(a: String, b: String, out: (String, String) -> String) {
println(out(a, b))
}
[출력결과]
Hello World! Arg1 Arg2
Hello World!!! Arg1 Arg2
■두 개의 람다식을 가진 함수의 사용
fun main() {
twoLambda({ a, b -> "First $a $b" }, {"Second $it"})
twoLambda({ a, b -> "First2 $a $b" }) {"Second2 $it"} // 위와 동일
}
fun twoLambda(first: (String, String) -> String, second: (String) -> String) {
println(first("OneParam", "TwoParam"))
println(second("OneParam"))
}
[출력결과]
First OneParam TwoParam
Second OneParam
First2 OneParam TwoParam
Second2 OneParam
■람다식에서 return 사용하기
fun main() {
retFunc()
}
inline fun inlineLambda(a: Int, b: Int, out: (Int, Int) -> Unit) {
out(a, b)
}
fun retFunc() {
println("start of retFunc") // ①
inlineLambda(13, 3) { a, b -> // ②
val result = a + b
if(result > 10) return // ③ 10보다 크면 이 함수를 빠져 나감
println("result: $result") // ④ 10보다 크면 이 문장에 도달하지 못함
}
println("end of retFunc") // ⑤
}
[출력결과]
start of retFunc
■람다식에서 라벨과 함께 return 사용하기
람다식 함수명 라벨이름@ {
...
retrun@라벨이름
}
fun main() {
retFunc()
}
fun inlineLambda(a: Int, b: Int, out: (Int, Int) -> Unit) {
out(a, b)
}
fun retFunc() {
println("start of retFunc")
inlineLambda(13, 3) lit@{ a, b -> // ① 람다식 블록의 시작 부분에 라벨을 지정함
val result = a + b
if(result > 10) return@lit // ② 라벨을 사용한 블록의 끝부분으로 반환
println("result: $result")
} // ③
println("end of retFunc") // ④ 이 부분이 실행됨
}
[출력결과]
start of retFunc
end of retFunc
■람다식에서 라벨과 함께 return 사용하기 :암묵적 라벨 (라벨 생략 가능)
fun retFunc() {
println("start of retFunc")
inlineLambda(13, 3) { a, b ->
val result = a + b
if(result > 10) return@inlineLambda
println("result: $result")
}
println("end of retFunc")
}
[REFERENCE]
Do it! 코틀린 프로그래밍: 03-2 함수형 프로그래밍 :11:00
Do it! 코틀린 프로그래밍: 03-3 고차 함수와 람다식
Do it! 코틀린 프로그래밍: 04-3 흐름의 중단과 반환