ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Kotlin] 코틀린 함수와 함수형 프로그래밍 3
    Kotlin/Function 2021. 9. 8. 20:47

    [Kotlin/Function] - [Kotlin] 코틀린 함수와 함수형 프로그래밍 1

    [Kotlin/Function] - [Kotlin] 코틀린 함수와 함수형 프로그래밍 2

    함수 타입 / 수신 객체 지정 함수 타입

     

    1. Function types

    함수의 파라메터와 return형 (함수의 시그니쳐) 에 해당하는 것이 function type이다.

    val onClick: () -> Unit

     

    onClick의 function type

    인자0개 return타입 Unit

    () -> Unit

     

    일반변수선언시 타입을 선언하듯이, 함수타입변수선언시 Function type을 선언하는데 

    Function타입 선언시의 내용

     

    • 리턴형이 Unit인 경우 생략되어서는 안된다

     

    • 선택적으로 receiver type(수신 객체)을 가질 수 있다 (Function literals with receiver)

    A.(B) -> C

    수신 객체인 A에서 호출될 수 있는 함수를 나타낸다.

    함수의 파라메터는 B타입, 리턴타입은 C

    밑에서 설명한다

     

    • suspending 함수는 suspend 수식어를 붙여야 한다.

    suspend () -> Unit 

    suspend A.(B) -> C //수신 객체 람다인 경우

     

    •  nullable한 function type을 지정하기 위해서는 바깥에 ()를 한번더 감싼후 ?를 지정한다.

     

    • 리턴값이 함수인 경우 (고차함수를 참조하는 경우 and 고차함수가 함수를 리턴하는 경우)

    return타입 부분을 ()로 감싸고 리턴하는 함수에 대한 function type을 작성

    (Int) -> ( (Int) -> Unit )

    (고차함수의 인자타입들) -> ( 고차함수가 리턴하는 함수의 타입의 function type )

    function type안에서 function type을 한번 더 작성하고 ()로 감싼다.

    //고차함수의 리턴 타입이 함수
    //고차함수의 리턴 함수 타입 -> 인자 String한개 리턴타입String
    fun highOrder(i: Int): (String) -> String {
        if (i >= 0) { //0포함 양수이면 대문자로 바꾸는 함수를 리턴
            return { str -> str.uppercase() }
        } else { //음수이면 소문자로 바꾸는 함수를 리턴
            return { str -> str.lowercase() }
        }
    }
    
    fun main() {
    
        val high = ::highOrder
        //동일한 식
        val high2: (Int) -> ((String) -> String) = ::highOrder
    
        //고차함수로부터 리턴된 일차함수
        val normal = high2(3) //양수인자 -> 대문자로 바꾸는 함수
        val normal2 = high2(-3) //음수인자 -> 소문자로 바꾸는 함수
    
        val upperString: String = normal("hello")
        val lowerString: String = normal2("WORLD")
    
        println(upperString)
        println(lowerString)
    }

     

    • type alias을 사용하여 자주 사용되는 function type 참조

    function type의 작성이 복잡하거나 자주사용되는 경우라면 type alias를 사용할 수 있다.

    typealias NoArgumentUnitReturn = (String) -> Unit
    
    fun main() {
        val v: NoArgumentUnitReturn = { str: String -> println(str) }
        v("hello")
    }


    2. Function literals with receiver(수신 객체 함수 리터럴)

     

    중요한 것은 아니지만 개념을 명확히 해보자.

    -Funtion type

    함수 타입

    -Function을 인스턴스화 하는 방법

    Function Literal(익명 함수, 람다표현식)

    참조가능한 함수( ::함수명) 등

     

    https://medium.com/@mook2_y2/%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%84%B0%EB%94%94-16-lambda-with-receiver-e265044206f9

    https://kotlinlang.org/docs/lambdas.html#function-literals-with-receiver

     

    • Fuction type with receiver ( 수신 객체가 지정된 Function type )   

    일반 함수타입 앞에 수신 객체가 지정된 함수 타입

     

    Person 클래스

    class Person(val name: String, val age: Int) {
    }

    Person 객체 수신 함수타입

    val test: Person.() -> Unit

     

    위의 수신 객체 지정(Person)함수타입의 함수를 호출할 때는 일반 함수타입의 인자제공에 추가적으로 Person객체를 맨앞의 인자로 넘겨줘야한다.

     

    수신 객체 람다식의 단어를 통해 함수 호출시점에 Person객체를 넘겨줌으로서 람다식의 바디에서 Person객체를 this로 사용할 수 있다. 또한 this를 생략하고 Person의 프로퍼티를 참조하는 것이 가능하다.

     

    코드를 보자.

     

    디컴파일 코드를 확인해보자

    val  변수 : 수신 객체 함수 타입 =수신 객체 지정 람다식

    val  변수2 : 함수 타입 = 람다식

     

    문법은 다르지만 모두 똑같이 Function1 인터페이스로 구현되는 것을 볼 수 있다.

    (Function 인터페이스 이전 포스팅들 참고)

    수신 객체 함수 타입은 확장함수 형식으로 사용해도 실제로 일반 형식으로 호출되는 것을 볼 수 있다.

     

     

    그렇다면 수신 객체 지정 람다식을 왜 사용할까?

     

    this를 생략하여 멤버를 호출할 수 있기 때문에 가독성이 좋아지고, 불필요한 코드 수고를 덜어줄 수 있다. 

    또한 수신 객체 지정 함수타입은 확장 함수처럼 사용될 수 있다. 확장 함수처럼 사용되어 수신 객체를 가지고 어떠한 처리를 하는 코드임을 느낄 수 있다.

     

    또한 기본 라이브러리나 extention function등을 참조해보면 함수형 프로그래밍으로 작성된 함수가 없는게 없다.

     

    다음 포스팅에서 scope function을 다뤄보도록 하겠다.

     

     

     

     

    댓글

Designed by Tistory.