ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 8장 - 고차 함수 : 파라미터와 반환 값으로 람다 사용
    Kotlin/코틀린인액션요약 2022. 9. 19. 00:01
    728x90

    8장에서 다루는 내용

    - 함수 타입

    - 고차 함수와 코드를 구조화할 때 고차 함수를 사용하는 방법

    - 인라인 함수

    - 비로컬 return과 레이블

    - 무명 함수

     

    고차 함수 정의

    고차 함수는 다른 함수를 인자로 받거나 함수를 반환하는 함수입니다.

    코틀린에서는 람다나 함수 참조를 사용해 함수를 값으로 표현할 수 있습니다.

     

    예를 들어 표준 라이브러리 함수인 filter는 술어 함수를 인자로 받으므로 고차 함수입니다.

    list.filter{x > 0 }

     

    간단한 고차 함수 정의하기

    fun twoAndThree (operation : (Int, Int) -> Int){
    	val result = operation(2,3)
        println("The result is ${result}")
    }
    
    twoAnddThree{a,b -> a+b}
    // The result is 5

     

    자바에서 코틀린 함수 타입 사용

    자바8 이상에서는 람다식을 사용하면 자동으로 함수 타입의 값으로 변환됩니다.

     

    하지만 자바 7 이하에서는 invoke 메서드를 구현하는 익명 클래스를 넘겨야 합니다.

     

     

    함수를 반환하는 함수 정의하기

    enum class Delivery {STANDARD, EXPEDITED}
    
    class Order(val itemCount : Int)
    
    fun getShippingCostCalculator(
        delivery: Delivery) : (Order) -> Double {
        if (delivery == Delivery.EXPEDITED) {
            return { order -> 6 + 2.1 * order.itemCount }
        }
        return { order -> 1.2 * order.itemCount }
    }
    
    fun main() {
        val calculator = getShippingCostCalculator(Delivery.EXPEDITED)
        println(calculator(Order(3)))
    }

    Order를 받아서 Double을 반환하는 함수입니다.

     

    람다를 활용한 중복 제거

    전략 패턴에서 만약 람다 식이 없다면 인터페이스를 선언하고 구현 클래스를 통해 전략을 정의해야 합니다.

    하지만 함수 타입을 언어가 지원하면 일반 함수 타입을 사용해 전략을 표현할 수 있고 경우에 따라 다른 람다식을 넘김으로써 여러 전략을 전달할 수 있습니다.

     

    고차 함수의 성능

    자바에서는 람다식을 활용하면 루프와 조건문을 사용할 때 보다 느려지는데 코틀린은 어떨까요?

    inline 변경자를 어떤 함수에 붙이면 컴파일러는 그 함수를 호출하는 모든 문장을 함수 본문에 해당하는 바이트코드로 바꿔치기해줍니다.

     

    어떤 함수를 inline으로 선언하면 그 함수의 본문이 인라인 됩니다.

    다른 말로 함수를 호출하는 코드를 함수 본문을 번역한 바이트코드로 컴파일됩니다.

     

     

    컬렉션 연산 인라이닝

    filter와 map은 인라인 함수입니다.

    따라서 일반적인 반복문을 사용하는 것과 바이트코드가 거의 동일합니다.

     

    하지만 처리할 원소가 많아지면 중간 리스트를 사용하는 비용이 커질 수 있습니다.

    이때 리스트를 시퀀스로 사용하면 중간 리스트로 인한 부가 비용은 줄어들지만 람다를 저장해야 하기 때문에 인라인 되지 않습니다.

    따라서 크기가 작은 컬렉션은 오히려 시퀀스를 사용하면 성능이 더 나빠질 수 있습니다.

     

     

    자바의 try-with-resources

    코틀린의 use라는 함수를 사용할 수 있습니다.

    fun readFirstLineFromFile(path: String) : String{
    	BufferedReader(FileReader(path)).use{ br ->
    		return br.readLine()
    	}
    }

    use 함수는 closeable 자원에 대한 확장 함수이며 람다를 인자로 받습니다.

    이때 예외가 발생한 경우에도 자원을 확실하게 닫아줍니다.

     

     

    고차 함수 안에서 흐름 제어

    fun lookForAlice(people : List<Person>{
    	people.forEach{
    		if(it.name == "Alice"){
    			println("Found!!")
    			return
    		}
    	}
        println("Alice is not Found")
    }

    return을 하면 람다로부터 반환되는 게 아니라 람다를 호출하는 함수가 실행을 끝나고 반환합니다.

     

    이렇게 자신을 둘러싸고 있는 블록보다 더 바깥에 있는 다른 블록을 반환하게 만드는 return문을 넌로컬 return이라고 부릅니다.

     

    레이블을 사용한 return 

    fun lookForAlice(people : List<Person>{
    	people.forEach label@{
    		if(it.name == "Alice"){
    			println("Found!!")
    			return@label
    		}
    	}
        println("Alice is not Found")
    }

     

    댓글

Designed by Tistory.