본문 바로가기
java & kotlin

[kotlin] 람다와 invoke

by algosketch 2021. 12. 24.

※ 람다를 사용하는 방법에 대해서는 자세히 다루지 않습니다.

 

람다를 받는 함수를 정의하는 방법

fun main(args: Array<String>) {
    doSomething{ a, b ->
        println("a + b = ${a + b}")
    }
    
    // 파라미터를 사용하지 않는 경우
    doSomething{ _, b ->
        println("b = ${b}")
    }
}

fun doSomething(action: (a: Int, b: Int)->(Unit)) {
    action(2, 3)
}

 람다 파라미터의 타입은 (파라미터: 타입)->(반환 타입) 형식이다. 위 코드와 같이 정의하고 사용할 수 있다. 만약 사용하지 않는 파라미터가 있다면 _ 기호를 사용해 명시할 수 있다.

 

인스턴스를 함수처럼 사용하는 방법

fun main(args: Array<String>) {
    val add = Add()
    add.invoke(2, 3)
    add(2, 3)
}

class Add {
    operator fun invoke(a: Int, b: Int) {
        println("a + b = ${a + b}")
    }
}

 클래스 내부에 invoke 메소드를 구현하면 인스턴스 이름과 () 의 조합으로 invoke 함수를 호출할 수 있다. 인스턴스.invoke() 로 호출하는 것과 동일하다. invoke 메소드 앞에는 operator 키워드를 붙여주어야 한다.

 

Java 에서 람다는 어떻게 컴파일 될까?

fun main(args: Array<String>) {
    doSomething(
            object : Function2<Int, Int, Unit> {
                override fun invoke(p1: Int, p2: Int) {
                    println("p1 + p2 = ${p1 + p2}")
                }
            }
    )
}

fun doSomething(action: (a: Int, b: Int)->(Unit)) {
    action(2, 3)
}

// FunctionN 인터페이스
// P1, P2, P3, ... , N : 파라미터 타입
// R : 반환 타입
// Function1
interface Function1<in P1, out R> {
    operator fun invoke(p1: P1) : R
}

 

 람다는 Java 에서 위와 같은 코드로 해석되어 컴파일 된다. 따라서 Java 와 Kotlin 사이에 호환이 가능하다. FunctionN 인터페이스는 N + 1 개의 타입 파라미터를 받는다. N 개는 invoke 메소드의 파라미터의 타입이고 나머지 한 개는 invoke 메소드의 반환 타입이다. in 과 out 키워드에 대해서 궁금하다면 제네릭, 공변성, 반공변성에 대해서 찾아보면 된다.

 그런데 어째서인지 FunctionN 과 비슷한 인터페이스를 직접 정의해서 넘겨주었을 때는 컴파일이 안 된다...