Kotlin:関数をパラメーターとして別の関数に渡す方法は?


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) }) }
ジェイソンMinard

1
同じクラス内で操作している場合、クラスに属している関数を渡すことができるようです。kotlin1.1以降は、次のようにして実行できますthis::function
Joe Maher

1
さらに、関数パラメーターをヌル可能にする場合は、型宣言を括弧で囲み、最後に疑問符を付けます。例bar: ((m: String) -> Unit)?
Aba

1
@MartyMillerはそうではありません。パラメータmはfoo用で、他のパラメータは変数barで関数に渡される関数タイプのパラメータ名です。
ジェイソンミナード2018

12

パラメータとしてのメンバー関数について:

  1. Kotlinクラスは静的メンバー関数をサポートしていないため、次のようにメンバー関数を呼び出すことはできません:Operator :: 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
現在のKotlinでは、メンバー関数を参照として使用できます。この回答を更新してください。
ジェイソンミナード2017

コンパニオンオブジェクトの呼び出しコードで関数を定義すると、コードが少し改善され、毎回新しいオペレーターのインスタンスが作成されることはありません。これは、Javaの静的な楽しみのように見えます
CAB

素晴らしい解決策です。これは、関数がクラス内にあるときに機能する唯一の方法です。私はそれを醜いとは思わないが美しい、ほとんど角度のテンプレート変数のように見えますが、コード用です。
gunslingor

4

Kotlin 1.1

::メソッドを参照するために使用します。

お気に入り

    foo(::buz) // calling buz here

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

4

メソッド名の前に「::」を使用するだけです

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

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

foo(::bar) 出力Hello World


このコードはコンパイルされません。「function()」にはパラメーターが必要です
Giuseppe Giacoppo


1

setterメソッドとgetterメソッドを渡したい場合。

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)

を使用して、これをもう少しドライにすることもでき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ではサポートされていません。これが追加すべき優れた機能になるかどうかについては、議論が交わされています。私は個人的にそうすべきだと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.