Kotlin: bagaimana cara meneruskan fungsi sebagai parameter ke yang lain?

141

Fungsi yang diberikan foo:

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

Kita bisa:

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

Sekarang, katakanlah kita memiliki fungsi berikut:

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

Apakah ada cara saya bisa meneruskan "buz" sebagai parameter ke "foo"? Sesuatu seperti:

foo("a message", buz)
mhshams
sumber

Jawaban:

199

Gunakan ::untuk menandakan referensi fungsi, dan kemudian:

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)
}

Karena Kotlin 1.1 Anda sekarang dapat menggunakan fungsi yang merupakan anggota kelas (" Bound Callable Referensi "), dengan mengawali awalan operator referensi fungsi dengan instance:

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

foo("hi", thatOtherThing::buz)

foo("hi", this::buz)
Jayson Minard
sumber
1
tolong perbaiki saya jika saya salah tetapi tampaknya hanya fungsi tingkat atas (yaitu bukan milik kelas) yang dapat diteruskan dengan cara ini; metode kelas tidak bisa :-(
Jaja Harris
7
Referensi anggota dapat diedarkan tetapi itu akan menjadi fungsi 2 parameter dalam kasus ini dengan parameter pertama yang membutuhkan turunan dari kelas. Cara yang lebih baik adalah membungkus fungsi anggota dengan lambda yang ditutup di kelas. Dengan asumsi semua hal di atas ada di kelas: fun something() { foo("hi", { buz(it) }) }
Jayson Minard
1
Tampaknya fungsi-fungsi yang termasuk dalam kelas dapat diteruskan jika Anda beroperasi dalam kelas yang sama, mulai dari kotlin 1.1 Anda dapat melakukannya denganthis::function
Joe Maher
1
Selain itu, jika Anda ingin membuat parameter fungsi nullable, cukup bungkus deklarasi tipe dalam tanda kurung dengan tanda tanya di akhir. misalnyabar: ((m: String) -> Unit)?
Aba
1
@ MartyMiller mereka tidak. Parameter muntuk foo, parameter lainnya adalah nama parameter dari jenis fungsi yang diteruskan dalam bilah variabel ke fungsi.
Jayson Minard
12

Tentang fungsi anggota sebagai parameter:

  1. Kelas Kotlin tidak mendukung fungsi anggota statis, sehingga fungsi anggota tidak dapat dipanggil seperti: Operator :: add (5, 4)
  2. Oleh karena itu, fungsi anggota tidak dapat digunakan sama dengan fungsi kelas satu.
  3. Pendekatan yang berguna adalah membungkus fungsi dengan lambda. Itu tidak elegan tetapi setidaknya itu berfungsi.

kode:

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) })
}
Rui Zhou
sumber
4
Di Kotlin saat ini, Anda sekarang dapat menggunakan fungsi anggota sebagai referensi. Anda sekarang harus memperbarui jawaban ini.
Jayson Minard
Dengan mendefinisikan fungsi dalam kode panggilan objek pendamping menjadi sedikit lebih baik dan tidak ada instance baru dari Operator dibuat setiap waktu. Ini akan terlihat seperti kesenangan statis di Jawa
CAB
Solusi hebat, ini adalah satu-satunya cara yang saya temukan yang berfungsi ketika fungsi berada dalam kelas. Saya tidak menganggapnya jelek tapi indah, hampir terlihat seperti variabel template sudut tetapi untuk kode.
Gunling atau
4

Kotlin 1.1

gunakan ::untuk metode referensi.

Suka

    foo(::buz) // calling buz here

    fun buz() {
        println("i am called")
    }
Menghubungkan kehidupan dengan Android
sumber
4

Cukup gunakan "::" sebelum nama metode

fun foo(function: () -> (Unit)) {
   function()
}

fun bar() {
    println("Hello World")
}

foo(::bar) Output :Hello World

erluxman
sumber
kode ini tidak dikompilasi. "function ()" memerlukan parameter
Giuseppe Giacoppo
1

Jika Anda ingin lulus metode setter dan pengambil .

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

Pemakaian:

private var width: Int = 1

setData({ width = it }, { width })
CoolMind
sumber
1

Jawaban Jason Minard adalah jawaban yang bagus. Ini juga dapat dicapai dengan menggunakan a lambda.

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

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

Yang bisa disebut dengan foo("a message", buz).

Anda juga dapat membuatnya lebih KERING dengan menggunakan a typealias.

typealias qux = (m: String) -> Unit

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

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

Contoh lain:

 fun foo(x:Int, Multiply: (Int) -> (Int)) {
    println(Multiply(x))
 }
 fun bar(x:Int):Int{
    return  x * x
 }
 foo(10, ::bar)
Erik K.
sumber
-7

Fungsi kelas satu saat ini tidak didukung di Kotlin. Ada perdebatan tentang apakah ini akan menjadi fitur yang baik untuk ditambahkan. Saya pribadi berpikir mereka harus.

ajselvig
sumber