Котлін: як передати функцію в якості параметра іншому?


141

Дана функція foo:

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

Ми можемо зробити:

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

Тепер скажемо, що ми маємо таку функцію:

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

Чи є спосіб передати "buz" як параметр до "foo"? Щось на зразок:

foo("a message", buz)

Відповіді:


199

Використовуйте ::для позначення посилання на функцію, а потім:

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

Оскільки Kotlin 1.1 тепер ви можете використовувати функції, які є членами класу (" Пов'язані посилання, що викликаються "), префіксуючи оператор посилань функції на екземпляр:

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

foo("hi", thatOtherThing::buz)

foo("hi", this::buz)

1
будь ласка, виправте мене, якщо я помиляюся, але здається, що таким чином можна передавати лише функції вищого рівня (тобто не належать до класу); Класні методи не можуть :-(
Jaja Harris

7
Посилання члена може бути передано навколо, але це була б функція параметра 2 у цьому випадку з першим параметром, що вимагає екземпляр класу. Кращий спосіб - обгорнути функцію члена лямбда, що закрилася на уроці. Якщо припустити, що все вище сказане було в класі: fun something() { foo("hi", { buz(it) }) }
Джейсон Мінард

1
Здається, що функції, які належать до класу, можна передавати, якщо ви працюєте в тому ж класі, як у kotlin 1.1, ви можете це зробитиthis::function
Joe Maher,

1
Крім того, якщо ви хочете зробити параметр функції нульовим, просто загортайте декларацію типу в дужки з позначкою питання в кінці. наприкладbar: ((m: String) -> Unit)?
Аба

1
@MartyMiller вони не є. Параметр mпризначений для foo, інший параметр - це назва параметра параметра типу функції, переданого у змінному рядку до функції.
Джейсон Мінард

12

Про функцію члена як параметр:

  1. Клас Котліна не підтримує статичну функцію члена, тому функцію члена не можна викликати так: Оператор :: add (5, 4)
  2. Тому функцію-члена не можна використовувати так само, як функцію першого класу.
  3. Корисний підхід - обмотати функцію лямбда. Це не елегантно, але принаймні працює.

код:

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

4
У поточному Котліні тепер ви можете використовувати функцію члена в якості посилання. Тепер слід оновити цю відповідь.
Джейсон Мінард

Визначаючи функції в коді супутнього об'єкта, виклик коду стає трохи кращим, і кожен раз не створюється новий екземпляр Оператора. Це виглядатиме як статична забава на Java
CAB

Чудове рішення, це єдиний спосіб, який я знайшов, що працює, коли функція знаходиться в класі. Я не вважаю це некрасивим, але красивим, майже виглядає як кутова змінна шаблону, але для коду.
зброяр


4

Просто використовуйте "::" перед назвою методу

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

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

foo(::bar) Вихід :Hello World


цей код не компілюється. "function ()" вимагає параметра
Джузеппе Джакоппо


1

Якщо ви хочете передати сетер та методи геттера .

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

Використання:

private var width: Int = 1

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

1

Відповідь Джейсона Мінарда хороша. Цього можна досягти також за допомогою а lambda.

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

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

Яку можна назвати с foo("a message", buz).

Ви також можете зробити це трохи СУХО, використовуючи a typealias.

typealias qux = (m: String) -> Unit

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

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

0

Ще один приклад:

 fun foo(x:Int, Multiply: (Int) -> (Int)) {
    println(Multiply(x))
 }
 fun bar(x:Int):Int{
    return  x * x
 }
 foo(10, ::bar)

-7

Функції першого класу в Котліні зараз не підтримуються. Проводилися дискусії щодо того, чи можна це додати. Я особисто думаю, що вони повинні.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.