Kotlin - 람다, 고차 함수

이동수·2024년 9월 25일

Kotlin

목록 보기
10/33
post-thumbnail

Lambda

사용하는 이유

  • 코드의 간결함 추구

사용하는 곳

특징

  • 람다식, 람다함수를 지칭하는 표현으로, 익명함수를 나타냄
  • 람다함수는 고차함수의 매개변수나 리턴값으로 사용 가능
  • 익명함수를 작성하는 간단한 방법
  • 이름없는 함수라고도 불림

사용법

  • 람다함수는 반드시 { }로 표현
  • var a : = {} 처럼 변수는 = { 람다 } 처럼 많이 쓰임
  • 람다함수는 fun 과 함수이름을 명시하지 않고 축약형으로 선언
    • { 매개변수 → 함수내용 }

    • { }안에 →가 있으면 왼쪽은 매개변수, 오른쪽은 함수의 내용

    • 매개변수 타입을 선언할때 추론할수 있으면 생략 가능

      val functionType: (Int) -> Boolean = {x: Int-> x < 20 }
      val functionType: (Int) -> Boolean = {x -> x < 20 } //Type 추론으로 생략 가능
      
  • 함수의 반환 값은 함수 구현 코드에서 맨 마지막 표현식
    • 맨 마지막이 print()이면 반환값이 없다는뜻임
  • it은 반드시 타입추론이 가능해야함
    • 파라미터가 2개면 못씀

    • 파라미터가 반드시 한개일때만 it 사용가능

      //it 사용 불가
      val singleParameter: (Int,Int) -> Int = { it * it }
      
  • {it → itit}처럼 it을 사용 하지않고 it이름을 바꿔주어도 된다. {age → age age}처럼
  • 멤버 참조를 이용한 호출
data class Member(var name: String, var age: Int)
val memberRef1: (Member) -> String = { member: Member -> member.toString() }
val memberRef2: (Member) -> String = { it.toString() } //제일 굳
val memberRef3: (Member) -> String = Member::toString
fun main(){
 val memberObj= Member("Pyo In soo", 35)
 println(memberRef1(memberObj))
 println(memberRef2(memberObj))
 println(memberRef3(memberObj))
}
public inline fun <T, C : MutableCollection<in T>> Iterable<T>.filterTo(
		destination: C,
		predicate: (T) -> Boolean): C { //- - - -> lambda를 파라미터로 받는다
for (element in this) if (predicate(element)) destination.add(element)
return destination
}

t,c어떤 함수가 들어올지 모름

코틀린의 타입 추론으로 인해 변수타입을 지정하지 않아도 람다를 변수에 대입할 수 있다.

val sum = { x: Int, y: Int -> x + y }
val action = { println(42) }

위 경우 컴파일러는 sum과 action의 함수 타입임을 추론함

만약 각 변수에 구체적인 타입 선언을 추가하면 아래와 같이 쓸 수 있게 됨

val sum: (Int, Int) -> Int = { x, y -> x + y } //Int 파라미터를 2개 받아서 Int 값을 반환하는 함수
val action: () -> Unit = { println(42) } //아무 인자도 받지 않고 아무 값도 반환하지 않는 함수

함수 타입을 정의하려면 함수 파라미터의 타입을 괄호 안에 넣고, 그 뒤에 화살표 -> 를 추가한 다음, 함수의 반환 타입을 지정하면 된다.

(Int, String) → Unit (파라미터타입, 파라미터타입) → 반환타입


High-Order Function(고차함수)

특징

  • 파라미터로 함수를 전달받거나 함수를 반환하는 함수를 의미
    • 다른함수를 인수로 받거나, 함수를 반환하는 함수
    • 함수를 다르는 함수를 고차함수라고 한다.
  • 보통 람다식을 이용해 구현
fun List<Int>.filterOnCondition(funvariance: (Int) -> Boolean): ArrayList<Int>{
    val result = arrayListOf<Int>()
    for(item in this){
        if(funvariance(item)){ //true일 경우 추가
            result.add(item)
        }
    }
    return result
}

fun isMultipleOf(number: Int): Boolean{
    return (number % 5) == 0
}

fun main(){
    val list = arrayListOf<Int>()
    for (number in 1..50){
        list.add(number)
    }
    var resultList = list.filterOnCondition { isMultipleOf(it) }
    println("""$resultList""")
    resultList = list.filterOnCondition { it -> it % 5 == 0 }
    println("""$resultList""")
    resultList= list.filterOnCondition{ it % 5 == 0 }
    println("""$resultList""")
}
  • 함수형 언어에서는 함수도 '값(value)’으로 취급
  • 고차함수의 매개변수가 함수 타입이면 함수 호출 시 () 생략 가능

사용법

  • 함수의 맨 마지막 매개변수가 람다일때는 { }로 뺼 수 있다
    • highOrderFucRule(25, {it it}, {it > 15}) ——> highOrderFucRule(5, {it it}) {it > 15}

      package SeSAC_Test
      
      val array = arrayOf(10,39,40,35,34,34)
      fun highOrderFucRule(number: Int, parameterFun1: (Int) -> Int, parameterFun2: (Int) -> Boolean){
          val result1 = parameterFun1(number)
          val result2 = parameterFun2(result1)
          println("""result1 : $result1, result2: $result2""")
      }
      fun main(){
          array.filter{ x -> x > 10 }
              .forEach{ x -> println(x) }
          highOrderFucRule(25, {it * it}, {it > 15})
          highOrderFucRule(5, {it * it}) {it > 15}
          //highOrderFucRule(25) {it * it}, {it > 15} //error
      }
  • 람다를 리턴 할 수 있다
    • fun fourArithmeticOperations(char: Char) : (x: Int, y:Int) -> Int { }

    • val b = a(’-’)로 객체 만들어주고 b(3,5)로 숫자 넣어줘야 하는구만

      package SeSAC_Test
      
      fun a(char: Char): (Int,Int) -> Int { //{x:Int, y:Int} -> Int 에서 x,y생략한거
          return when(char){
              '-' -> {x,y -> x - y}
              else -> {x,y -> x/y}
          }
      }
      fun main() {
          val b = a('5')
          val b2 = a('-')
          println(b)
          println(b2)
          println(b(1, 5))
          println(b2(1, 5))
      }
      /* 출력
      Function2<java.lang.Integer, java.lang.Integer, java.lang.Integer>
      Function2<java.lang.Integer, java.lang.Integer, java.lang.Integer>
      0
      -4
       */
      
      data class Address(
          val city: String,
          val gu: String,
          val dong: String
      )
      
      class AddressFilters{
          var where : String = ""
          fun getP(): (Address) -> Boolean{
              val whereAddress = { it: Address -> it.city.startsWith(where)}
              return whereAddress
          }
      }
      fun main(){
          val addresses = listOf(
              Address("서울시", "금천구", "독산1동 새싹"),
              Address("부산시", "관악구", "독산2동 새싹"),
              Address("서울시", "강남구", "역삼3동 새싹"),
              Address("부산시", "부전구", "부번1동 새싹")
          )
          val addressSearch =  AddressFilters()
          addressSearch.where = "서울"
          println(addresses.filter(addressSearch.getP()))
      }
      
  • 함수 참조를 이용한 함수 전달
    fun fRef(argFun: (Int)-> Int){
        println("${argFun(15)}")
    }
    
    fun refFunName(x: Int): Int{
        return x*2
    }
    fun main(){
        fRef { it*2 } //츨력 30
        fRef (::refFunName ) //출력 30
    }
    

0개의 댓글