invoke란 이름 없이 간편하게 호출될 수 있는 함수이다.
class Person(var name: String) {
operator fun invoke() {
println("name : $name")
}
}
fun main(args: Array<String>): Unit {
val person = Person("Kotlin")
person()
}
결과
name : Kotlin
이 코드에서는 Person이라는 클래스에서 인자로 받은 문자열을 출력하는 invoke 함수가 선언되어 있다.
이 함수를 호출하기 위해서는 person 객체를 생성한뒤 person.invoke(str)
의 형태로 호출해야 할 것 같지만 invoke 함수는 해당 함수의 접근을 생략하고 호출이 가능하다.
따라서 person이라는 객체를 선언한뒤, 객체 내의 함수 이름인 invoke를 호출하지 않아도 invoke 함수가 호출이 된다.
즉, invoke를 이용해 자주 호출해야 하는 함수를 객체의 이름()
만으로도 호출할 수 있게 된다.
위의 예시에서 invoke 함수의 선언부를 보면 operator 키워드가 붙어있다.
코틀린은 이름을 부여한 함수임에도 불구하고 실행을 간편하게 할 수 있는 "연산자"라는 것을 제공한다.
예를 들어 더하기는 + 연산자로, 뺄셈은 - 연산자로 수행이 가능하다. invoke도 이러한 연산자에 포함되는 키워드이다.
그리고 이러한 연산자를 overloading 할 수 있도록 코틀린에서는 operator 키워드를 제공한다.
람다는 컴파일되면서 코틀린에 정의된 FunctionN(P1, P2, ... , PN)의 형태로 변환된다. 이때 N은 인자의 수를 의미한다.
그리고 이 function의 인터페이스에는 invoke만이 정의되어 호출노딘다.
아래는 람다 함수를 디컴파일한 코드이다.
// lambda
val convert = { x: Int -> x.toString() }
// compiled
val convert = object : Function1<Int, String> {
override fun invoke(p1: Int): String {
return p1.toString()
}
}
이 코드에서는 (Int) -> String 형태의 람다가 Function1<Int, String> 형태로 변환되고, 구현 내용이 override된 invoke 함수로 들어가는 것을 확인할 수 있다.
이러한 형태로 변환되기 때문에 convert.invoke(2)와 같이 호출하지 않고, convert(2) 와 같은 간편한 형태로 호출할 수 있게 된다.