在 Kotlin 中使用具有函数类型的函数接口

Using functional interfaces with function types in Kotlin

当从 Kotlin 调用 Java 代码时,有 SAM conversion 这样 Java 代码如下:

adapter.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view, int position) {
        // Do stuff here
    }
});

可以看起来像这样:

adapter.setOnClickListener { view, position ->
    // Do stuff
}

现在,我正在做一个 Kotlin 项目,我想定义一个功能接口作为事件监听器:

interface OnSomeActionListener {

    fun onSomeAction(parameter1: Int, parameter2: String)

}

SomeClass中我有一个设置监听器的函数:

    ...

    private var onSomeActionListener: OnSomeActionListener? = null

    fun setOnSomeActionListener(listener: OnSomeActionListener) {
        onSomeActionListener = listener
    }

    ...

当我创建这个 class 的实例并尝试调用 setter 函数时,我是这样做的:

val thing = SomeClass()

thing.setOnSomeActionListener(object : OnSomeActionListener {
    override fun onSomeAction(parameter1: Int, parameter2: String) {
        // Do stuff here
    }
})

我知道 Kotlin 有函数类型,因此不支持来自 this one.

等不同网站的 SAM 转换

我读过一些关于函数类型的内容,但我以前没有使用过它们。

我该如何重写我的代码才能像这样调用 setter 函数?

val thing = SomeClass()

thing.setOnSomeActionListener { parameter1, parameter2 ->
    // Do stuff here
}

.

嗯,像这样:

// declare a variable of nullable function type:
var onSomeActionListener: ((Int, String) -> Unit)? = null

// declare higher-order function:
fun setOnSomeActionListener(listener: (Int, String) -> Unit) {
    onSomeActionListener = listener
}

// set listener:
val listener: (Int, String) -> Unit = { p1, p2 -> { /* some stuff */ } }
setOnSomeActionListener(listener)

// or in one line:
setOnSomeActionListener { p1, p2 -> { /* some stuff */ } }

更多信息:Higher-Order Functions and Lambdas

函数类型如下所示:

(Parameters) -> ReturnType

在您的情况下,您可以使用 (View, Int) -> Unit 而不是使用接口类型。它看起来像这样:

private var onSomeActionListener: ((View, Int) -> Unit)? = null

fun setOnSomeActionListener(listener: (View, Int) -> Unit) {
    onSomeActionListener = listener
}

private fun callSomeActionListener(view: View, position: Int) {
    onSomeActionListener?.invoke(view, position)
}

添加姓名

在函数类型中,您还可以为参数指定名称。这在幕后并没有太大变化,但他们可以在此处和调用代码中增加一些清晰度,这很好。

(view: View, position: Int) -> Unit

使用类型别名

为了避免每次都输入(View, Int) -> Unit,你可以定义一个类型别名:

typealias OnSomeActionListener = (view: View, position: Int) -> Unit

这样您的代码现在又看起来像这样了:

private var onSomeActionListener: OnSomeActionListener? = null

fun setOnSomeActionListener(listener: OnSomeActionListener?) {
    onSomeActionListener = listener
}   

并调用它:

val thing = SomeClass()

thing.setOnSomeActionListener { view, position ->
    // Do stuff here
}

如何定义接受函数和 returns 接口的函数?

fun makeOnSomeActionListener(f: (Int,String) -> Unit) = object : OnSomeActionListener {
    override fun onSomeAction(parameter1: Int, parameter2: String) = f(parameter1, parameter2)
}

接口将其工作委托给 f

那你可以写

val thing = SomeClass()

thing.setOnSomeActionListener(makeOnSomeActionLisener { parameter1, parameter2 ->
  // Do stuff here
})