Home > database >  How to use function receiver type with SAM interfaces in Kotlin
How to use function receiver type with SAM interfaces in Kotlin

Time:12-03

I'm coming from Java and am new to Kotlin. I try to understand how to use receiver type with lambdas specified as functional SAM interfaces.

Let the code speak for itself.

fun interface Delegator <T> {
    fun delegate(receiver: T)
}

fun <T> invokeWithDynamicReceiver(receiver: T, fn: T.() -> Unit) = receiver.fn()
fun <T> invokeWithSamInterface(receiver: T, fn: Delegator<T>) = fn.delegate(receiver)

fun dynamicReceiver() {
    invokeWithDynamicReceiver("Foo") { length } // Dynamic receiver
    invokeWithSamInterface("Foo") { it.length } // Can't bind receiver as "this"
}

How do I need to change the code to use the Delegator lambda with dynamic receiver?

CodePudding user response:

You can define the functions inside the Delegator as extension function, this way the receiver is passed as this to the lambda.

fun interface ExtensionDelegator <T, R> {
    fun T.delegate(): R
}

fun <T, R> invokeWithExtensionSamInterface(receiver: T, fn: ExtensionDelegator<T, R>): R =
    with(fn) { receiver.delegate() }

Alternatively, you can simply define the dynamic receiver with a typealias to achieve the same result.

typealias AliasDelegator<T, R> = T.() -> R

fun <T, R> invokeWithAliasSamInterface(receiver: T, fn: AliasDelegator<T, R>): R = fn.invoke(receiver)

On the use site, both approaches look the same.

fun main() {
    val result = invokeWithExtensionSamInterface("Foo") { length }
    println(result)

    val otherResult = invokeWithAliasSamInterface("Fizz") { length }
    println(otherResult)
}
  • Related