web-dev-qa-db-fra.com

Kotlin: comment passer une fonction à l'autre?

Étant donné la fonction foo:

fun foo(m: String, bar: (m: String) -> Unit) {
    bar(m)
}

Nous pouvons faire:

foo("a message", { println("this is a message: $it") } )
//or 
foo("a message")  { println("this is a message: $it") }

Maintenant, disons que nous avons la fonction suivante:

fun buz(m: String) {
   println("another message: $m")
}

Est-il possible de passer "buz" comme paramètre à "foo"? Quelque chose comme:

foo("a message", buz)
71
mhshams

Utilisez :: pour désigner une référence de fonction, puis:

fun foo(m: String, bar: (m: String) -> Unit) {
    bar(m)
}

// my function to pass into the other
fun buz(m: String) {
    println("another message: $m")
}

// someone passing buz into foo
fun something() {
    foo("hi", ::buz)
}

Depuis Kotlin 1.1 , vous pouvez maintenant utiliser les fonctions membres de la classe ("Bound Callable References"), en préfixant l'opérateur de référence de fonction avec l'instance:

foo("hi", OtherClass()::buz)

foo("hi", thatOtherThing::buz)

foo("hi", this::buz)
110
Jayson Minard

A propos de la fonction membre en tant que paramètre:

  1. La classe Kotlin ne supporte pas la fonction membre statique, donc la fonction membre ne peut pas être invoquée comme: 
  2. Par conséquent, la fonction membre ne peut pas être utilisée comme la fonction de première classe.
  3. Une approche utile consiste à envelopper la fonction avec un lambda. Ce n'est pas élégant mais au moins ça marche.

code:

class Operator {
    fun add(a: Int, b: Int) = a + b
    fun inc(a: Int) = a + 1
}

fun calc(a: Int, b: Int, opr: (Int, Int) -> Int) = opr(a, b)
fun calc(a: Int, opr: (Int) -> Int) = opr(a)

fun main(args: Array<String>) {
    calc(1, 2, { a, b -> Operator().add(a, b) })
    calc(1, { Operator().inc(it) })
}
5
Rui Zhou

apparemment ce n'est pas encore supporté. 

plus d'informations: 

http://devnet.jetbrains.com/message/5485180#5485180

http://youtrack.jetbrains.com/issue/KT-1183

3
mhshams

Il suffit d'utiliser "::" devant le nom de la méthode comme paramètre  

fun main(args: Array<String>) {
    runAFunc(::runLines)
}


fun runAFunc(predicate: (Int) -> (Unit)) {
   val a = "five"
   if (a == "five") predicate.invoke(5) else predicate.invoke(3)

}

fun runLines(numbers: Int) {
    var i = numbers
    while (i > 0) {
        println("printed number is $i")
        i--
    }
}
1
erluxman

La réponse de Jason Minard est bonne. Ceci pourrait également être réalisé en utilisant une lambda.

fun foo(m: String, bar: (m: String) -> Unit) {
    bar(m)
}

val buz = { m: String ->
    println("another message: $m")
}

Qui peut être appelé avec foo("a message", buz).

Vous pouvez également rendre cela un peu plus DRY en utilisant un typealias.

typealias qux = (m: String) -> Unit

fun foo(m: String, bar: qux) {
    bar(m)
}

val buz: qux = { m ->
    println("another message: $m")
}
0
flesk

Si vous voulez passer les méthodes setter et getter .

private fun setData(setValue: (Int) -> Unit, getValue: () -> (Int)) {
    val oldValue = getValue()
    val newValue = oldValue * 2
    setValue(newValue)
}

Usage:

private var width: Int = 1

setData({ width = it }, { width })
0
CoolMind

Kotlin 1.1 

utilisez :: pour référencer la méthode.

comme

    foo(::buz) // calling buz here

    fun buz() {
        println("i am called")
    }