Passing lambda instead of interface

前端 未结 5 1801
执念已碎
执念已碎 2020-12-08 12:44

I have created an interface:

interface ProgressListener {
    fun transferred(bytesUploaded: Long)
}

but can use it only as an anonymous clas

5条回答
  •  轮回少年
    2020-12-08 13:31

    UPDATED: September 7th, 2020

    As the Kotlin documentation for the Kotlin 1.4 release points out:

    Before Kotlin 1.4.0, you could apply SAM (Single Abstract Method) conversions only when working with Java methods and Java interfaces from Kotlin. From now on, you can use SAM conversions for Kotlin interfaces as well. To do so, mark a Kotlin interface explicitly as functional with the fun modifier.

    fun interface Operation1 {
        operator fun invoke(x: String): String
    }
    
    fun interface Operation2 {
        fun doSomething(x: Int): String
    }
    
    val operation1 = Operation1 { "$it world!" }
    val operation2 = Operation2 { "$it world!" }
    
    fun main() {
        // Usage: First sample.
        println(operation1("Hello"))
        println(operation2.doSomething(0))
        // Usage: Second sample.
        println(Operation1 { "$it world!" }("Hello"))
        println(Operation2 { "$it!" }.doSomething(0))
    }
    

    You can read more about functional interfaces here.

    Previous solution:

    Declare a typealias, inject it somewhere and invoke it later on:

    internal typealias WhateverListener = (String) -> Unit
    

    and then we inject that typealias to our class:

    class Gallery constructor(private val whateverListener: WhateverListener) {
        
        ...
        
        galleryItemClickListener.invoke("hello")
    
        ...
    }
    

    so we have our lambda:

    val gallery = Gallery { appNavigator.openVideoPlayer(it) }
    

    Credits to my colleague Joel Pedraza, who showed me the trick while trying to find a solution <3.

    NOTE: Check out the Kotlin documentation in case you want to know when to use either functional interfaces (lambdas) or type aliases.

提交回复
热议问题