4 votes

Comment utiliser les lambdas avec les interfaces fonctionnelles et assigner directement une lambda à une variable en Kotlin

J'ai ce code:

paquet org.medianik.kotlindoc

fun main(){
    val creator:Creatable = toCreatable(::Created)// Ok. Compile, et fonctionne bien
    val creator1:Creatable = ::Created // Erreur de compilation
    val creator2:Creatable = ::Created as Creatable // ok assez pour compiler, mais il y a une exception d'exécution
    val c = creator.create(5)
    val creator3:Creatable = toCreatable(c::doSmth1) // Ok. Compile, fonctionne bien
    val creator4:Creatable = c::doSmth1 // Erreur de compilation
    val creator5:Creatable = c::doSmth1 as Creatable // Encore une fois assez bon pour compiler, mais il y a une exception d'exécution
    val creator6:Creatable = Creatable { i -> Created(i) } // Fonctionne bien, mais ce n'est pas ce que je veux
}

fun toCreatable(c:Creatable) = c

fun interface Creatable{
    fun create(i: Int) : Created
}
class Created(private var i: Int){
    fun doSmth1(add: Int): Created{
        return this.also { i+=add }
    }
}

Exception pour creator2:

Exception in thread "main" java.lang.ClassCastException: class org.medianik.kotlindoc.MainKt$main$creator2$1 ne peut pas être cast en class org.medianik.kotlindoc.Creatable (org.medianik.kotlindoc.MainKt$main$creator2$1 et org.medianik.kotlindoc.Creatable sont dans un module non nommé du chargeur 'app')

Exception pour creator5:

Exception in thread "main" java.lang.ClassCastException: class org.medianik.kotlindoc.MainKt$main$creator5$1 ne peut pas être cast en class org.medianik.kotlindoc.Creatable (org.medianik.kotlindoc.MainKt$main$creator5$1 et org.medianik.kotlindoc.Creatable sont dans un module non nommé du chargeur 'app')

Je n'ai aucune idée de comment faire fonctionner creator1/4 avec une référence de méthode. Y a-t-il des moyens de les faire fonctionner? Parce que cela me semble sans sens: si vous passez une référence de méthode à une fonction en tant qu'argument -- cela se convertit en une interface, sinon non. Comment cela fonctionne-t-il?

Y a-t-il des castings spéciaux pour les fonctions vers les interfaces?

0voto

Jens Baitinger Points 387

J'ai copié votre code dans IntelliJ et j'ai également obtenu des erreurs dans les lignes

 val creator:Creatable = toCreatable(::Created)
 val creator3:Creatable = toCreatable(c::doSmth1)

Le problème est que Creatable est une Interface nommée qui a la même signature de méthode que la classe Created mais cette classe n'implémente pas l'interface.

Remarquez, une fonction ne met pas en œuvre une interface, même si elles ont une signature.

Vous pourriez déclarer à la place d'une interface un type de fonction. Remarquez, ce n'est pas la même chose, mais elles peuvent être manipulées presque de la même manière.

typealias Creatable = (Int) -> Created

ou vous pourriez écrire un wrapper acceptant un tel type de fonction:

fun toCreatable(c:(Int) -> Created) = object: Creatable {
    override fun create(i: Int): Created {
        return c(i)
    }
}

Cette fonction accepte une fonction et renvoie un objet qui implémente effectivement l'interface.

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