92 votes

Passer lambda au lieu d'interface

J'ai créé une interface:

 interface ProgressListener {
    fun transferred(bytesUploaded: Long)
}
 

mais ne peut l'utiliser que comme classe anonyme, pas lambda

 dataManager.createAndSubmitSendIt(title, message,
object : ProgressListener {
    override fun transferred(bytesUploaded: Long) {
        System.out.println(bytesUploaded.toString())
    }
})
 

Je pense que cela devrait être une possibilité de le remplacer par lambda:

 dataManager.createAndSubmitSendIt(title, message, {System.out.println(it.toString())})
 

Mais j'obtiens une erreur: Type mismatch; required - ProgressListener, trouvé - () -> Unité?

Qu'est-ce que je fais mal?

87voto

marstran Points 9298

Comme @ zsmb13 l'a indiqué, les conversions SAM ne sont prises en charge que pour les interfaces Java.

Vous pouvez créer une fonction d’extension pour que cela fonctionne bien:

 // Assuming the type of dataManager is DataManager.
fun DataManager.createAndSubmitSendIt(title: String, 
                                      message: String, 
                                      progressListener: (Long) -> Unit) {
    createAndSubmitSendIt(title, message,
        object : ProgressListener {
            override fun transferred(bytesUploaded: Long) {
                progressListener(bytesUploaded)
            }
        })
}
 

34voto

zsmb13 Points 36441

Kotlin ne supporte SAM conversions pour les interfaces de Java.

... notez que cette fonctionnalité fonctionne uniquement pour Java interop; depuis Kotlin a correcte des types de fonction, la conversion automatique de fonctions dans les implémentations de Kotlin interfaces est inutile et, par conséquent, non pris en charge.

-- La documentation officielle

Si vous souhaitez utiliser une lambda dans le paramètre, faites votre prise de fonction d'un paramètre de fonction au lieu d'une interface. (Du moins pour le moment. L'appui SAM conversions de Kotlin des interfaces est une discussion en cours, il a été l'un des futurs possibles de fonctionnalités à la Kotlin 1.1 flux en direct.)

16voto

m3n0R Points 2333

Une autre solution consisterait à déclarer un typealias, à l'injecter quelque part et à l'invoquer. Voici l'exemple:

 internal typealias WhateverListener = (String) -> Unit
 

et ensuite nous injectons ces typealias à notre classe:

 class Gallery constructor(private val whateverListener: WhateverListener) {

    ...

    galleryItemClickListener.invoke("hello")

    ...
}
 

nous avons donc notre lambda:

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

Crédits à mon collègue Joel Pedraza, qui m'a montré le truc en essayant de trouver une solution <3.

10voto

Louis Tsai Points 113

Un peu tard pour le parti: au lieu de créer une interface, vous laissez la compilation en créer une en prenant directement une fonction plutôt qu'une interface dans votre datamanager, comme ceci:

 fun createAndSubmitSendIt(title: String, message: String, transferred: (Long) -> Unit) {
    val answer = TODO("whatever you need to do")
    transferred(answer)
}
 

et ensuite vous l'utilisez comme vous le souhaitez! Si je me souviens bien, ce que fait le compilateur kotlin / jvm revient à créer une interface.

J'espère que ça aide!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X