[Kotlin]고차함수와 람다식

dada·2021년 11월 25일
0

Kotlin

목록 보기
14/14
post-thumbnail

✅람다식 구조

  • 원래 람다는 이름이 없는 함수인데 변수에 대입해서 변수처럼 사용할 수 있음
  • 변수의 타입을 적어주는 것처럼 람다식의 선언 자료형을 적어준다
    이때, 람다의 인자로 Int형 타입이 들어가고 return타입도 Int형이니까 (Int,Int)->Int
  • 람다식 선언 자료형이 생략되었다면 람다식의 매개변수 타입은 생략될 수 없고, 반대로 람다식 선언 자료형이 명시되어있다면 매개변수 타입은 생략될 수 있음
  • 람다식의 처리 내용이 여러줄일 경우는 마지막 표현식이 반환됨!

✅람다가 리턴하는 값과 자료형의 생략

  • 위에서 람다식 내용 여러줄이면 항상 마지막 표현식이 반환된다는거 주의!!
  • 자료형을 생략할 수 있는 방법은 3개다. 선언자료형과 매개변수 자료형 중 반드시 하나에는 자료형을 명시해줘야함. 두군데 모두 생략하면 에러다
  • 선언 자료형에서, 반환되는 리턴타입이 없으면, 즉 반환되는 자료형이 없으면 Unit으로 표현한다
  • 선언자료형에서 인자가 없는걸 표현할 땐 () 로 표현하고 매개변수도 작성 안하고 그냥 로직만 써준다

  • 인자에 람다를 사용한 고차함수의 예시다 여기서 sum:(Int,Int)->Int 는 sum이라는 변수의 선언 자료형이 람다이기 때문에 람다를 인자로 받고있고 return sum(a,b) 에서 람다식을 변수에 대입해서 사용할 수 있기때문에 가능한 것이다.

✅변수 이름으로 호출하기vs()로 호출하기

✔()로 호출하기

  • Lambda를 인자없이 Lambda()로 호출할떄는 리턴값인 true가 반환됨

✔변수 이름으로 호출하기

  • 인자가 없는 람다식을 담고 있는 변수를 이름으로 호출할 경우, 리턴값이 아니라 람다식의 코드블록이 그대로 멱살잡혀 끌려간다 생각하면 된다
  • 위에처럼 ()로 호출하는 경우와 차이가 있고 이 두 경우를 잘 이용하면 상황에 맞춰 즉시 실행할 필요가 없는 코드를 작성하는 경우 이름에 의한 호출 방법을 통해 필요할 때만 람다식 함수가 작동하도록 만들 수 있다.

✅람다가 아닌 함수를 람다식처럼 인자로 받기(참조)

  • sum이라는 함수는 람다식이 아닌데 funcParam이라는 함수의 람다식 선언자료형으로 표기된 3번째 인자로 넣으려고하면 오류가 발생한다. 그 이유는 sum은 람다식으로 작성된 함수가 아니기 때문이다
  • 람다식 함수가 아닌 함수를 함수의 인자로 사용할 수 있는 방법은, ::sum 의 참조방식으로 호출하면 람다식 형태로 호출받아서 매개변수로 사용할 수 있게 된다
  • 일반함수를 참조형으로 사용해서 람다식처럼 사용하면 다방면있게 활용가능

✅매개변수 개수에 따라 람다식을 구성하는 방법

✔매개변수가 없는 경우

✔매개변수가 한 개인 경우

✔매개변수가 두 개인 경우

  • 매개변수가 두개인 경우에는 it으로 대체하거나 생략할 수 없음

✔매개변수를 생략하는 경우

  • 매개변수에 디폴트 값이 있다거나 값을 생략하는 경우 _로 표시

✔일반 매개변수와 람다식 매개변수를 같이 사용

  • 매개변수가 여러개 있고 마지막 매개변수가 람다식 선언형일때 인자로 전달하는 경우 마지막 인자인 람다식의 {}를 () 밖으로 빼낼 수 있음 이건 규칙이다.
  • 그렇다면 매개변수에 람다식 선언형이 여러개 있으면? 무조권 마지막 인자인 람다만 소괄호 () 밖으로 빼낼 수 있고 나머진 안됨!

✅Sample code


package Lambda

fun main() {
    //1. 고차함수
    val res1 = sum(3, 2)
    val res2 = mul(sum(3, 2), 5)

    //2. 일반 변수에 람다식 할당
    //변수이지만 람다식을 리턴받는 변수이기 때문에 함수처럼 사용할 수 있음
    val multi: (Int, Int) -> Int = { a: Int, b: Int -> a * b }

    //3. 람다식이 할당된 변수는 함수처럼 사용 가능
    val result: Int
    result = multi(10, 20)

    //4. 자료형의 생략
    val test1: (Int, Int) -> Int = { a: Int, b: Int -> a * b }
    val test2 = { a: Int, b: Int -> a * b }
    val test3: (Int, Int) -> Int = { a, b -> a * b }

    //5. 반환자료형이 없거나 매개변수가 하나
    val test4: () -> Unit = { println("Hello") }
    val test5: (Int) -> Int = { a -> a * a }
    // val test5: Int -> Int = { a -> a * a }  ()생략이 안됨
    println(test4) //Function0<kotlin.Unit>
    println(test4())  //Hello

    // 6.선언부의 자료형 생략
    val test6 = { println("Hello") }
    //   val test7 = { a, b -> a * b } 선언자료형 생략시 매개변수 자료형 생략 불가
    val test7 = { a: Int, b: Int -> a * b }

    //7. 항상 마지막 부분이 반환값임
    val test8 = { a: Int, b: Int ->
        println("첫번째줄")
        println("두번째줄")
        println("세번째줄")
    }

    //8. 인자에 람다사용하는 고차함수
    fun test9(minus: (Int, Int) -> Int, b: Int, c: Int): Int {
        return minus(b, c)
    }

    test9({ a: Int, b: Int -> a - b }, 20, 10)  //함수의 인자로 람다식 사용

    //9. 람다 호출 ->()로 호출
    val test10 = callByValue(Lambda())
    println(test10)

    //10. 람다 호출 ->람다 이름으로 호출
    val test11 = callByValue2(otherLambda)
    println(test11)

    //11. 일반함수인걸 람다식처럼 매개변수 인자로 사용하고 싶을때
    // order(sum11,11,12)
    order(::sum11, 11, 12)

    //12. 매개변수가 없는 경우 () 생략
    noParam({ "Hi" })
    noParam() { "Hi" } //람다식이 하나 있는 경우 () 밖으로 {} 빼내오기 가능
    noParam { "Hi" } // () 밖으로 {} 빼내오고 () 생략 가능

    //13. 매개변수가 하나인 경우
    oneParam({ a -> a })
    oneParam() { a -> a }
    oneParam { a -> a }
    oneParam { "a+$it" } //it이 파라미터의 인자로 들어온 값 역할

    //14. 매개변수 두개
    moreParam { a, g -> a + g }

    //15. 마지막 인자가 람다인 경우 밖으로 빼낼 수 있음
    withArgs("a", "b", { a, b -> a + b })
    withArgs("a", "b") { a, b -> a + b }


}

fun withArgs(a: String, b: String, out: (String, String) -> String) {
    println(out(a, b))
}

fun noParam(out: () -> String) {
    println(out())
}

fun moreParam(out: (String, String) -> String) {
    println(out("", ""))
}

fun oneParam(out: (String) -> String) {
    println(out(""))
}

fun order(sum: (Int, Int) -> Int, a: Int, b: Int): Int {
    return sum(a, b)
}

fun sum11(a: Int, b: Int): Int {
    return a + b
}

fun callByValue2(b: () -> Boolean): Boolean {
    println("callByValue2")
    return b()
}

val otherLambda: () -> Boolean = {
    println("otherLambda")
    true
}


fun callByValue(b: Boolean): Boolean {
    println("callByValue")
    return b
}

val Lambda: () -> Boolean = {
    println("Lambda") //출력됨!! return이 안될뿐
    true
}

fun sum(a: Int, b: Int) = a + b
fun mul(a: Int, b: Int) = a * b
fun funFunc(): Int {
    return sum(2, 2) //함수의 반환값으로 함수 사용
}

참고
Do it! 코틀린 프로그래밍- 고차함수와 람다함수

profile
'왜?'라는 물음을 해결하며 마지막 개념까지 공부합니다✍

0개의 댓글