Kotlin:如何将函数作为参数传递给另一个函数?


140

给定函数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)

Answers:


198

使用::表示函数引用,然后:

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参数函数,第一个参数需要类的实例。更好的方法是用在类上关闭的lambda包装成员函数。假设以上所有内容均在课堂上: fun something() { foo("hi", { buz(it) }) }
Jayson Minard,2015年

1
如果您在同一个类中进行操作,似乎可以传递属于某个类的函数,从kotlin 1.1开始,您可以使用this::function
Joe Maher

1
另外,如果您想使函数参数为可空的,只需将类型声明括在括号中并在末尾带有问号。例如bar: ((m: String) -> Unit)?
Aba

1
@MartyMiller他们不是。该参数m用于foo,另一个参数是在变量栏中传递给函数的函数类型的参数名称。
Jayson Minard '18

12

关于成员函数作为参数:

  1. Kotlin类不支持静态成员函数,因此无法像以下那样调用成员函数:Operator :: add(5,4)
  2. 因此,成员函数不能与First-class函数一样使用。
  3. 一种有用的方法是用lambda包装函数。它并不优雅,但至少可以正常工作。

码:

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
在当前的Kotlin中,您现在可以使用成员函数作为参考。您现在应该更新此答案。
杰森·米纳德

通过在伴随对象中定义函数,调用代码会变得更好一点,并且每次都不会创建新的Operator实例。这看起来像是Java中的静态乐趣
CAB

很好的解决方案,这是我发现函数在类中时起作用的唯一方法。我不认为它丑陋但美观,几乎看起来像是一个有角度的模板变量,只是用于代码。
枪手


4

只需在方法名称前使用“ ::”

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

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

foo(::bar) 输出Hello World


此代码无法编译。“ function()”需要一个参数
Giuseppe Giacoppo,


1

如果要传递settergetter方法。

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

杰森·米纳德(Jason Minard)的答案很好。也可以使用来实现lambda

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

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

可以用来调用foo("a message", buz)

您也可以使用来使它更干燥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

Kotlin当前不支持一流的功能。关于是否添加一个好功能一直存在争议。我个人认为他们应该。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.