在Kotlin中使用功能类型的功能接口

时间:2017-07-12 08:47:38

标签: java lambda kotlin higher-order-functions kotlin-interop

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

    ...

当我创建这个类的实例并尝试调用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
}

3 个答案:

答案 0 :(得分:12)

函数类型如下所示:

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

答案 1 :(得分:0)

嗯,这样的事情:

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR),"static","media")

有关详细信息:Higher-Order Functions and Lambdas

答案 2 :(得分:0)

如何定义接受函数并返回接口的函数?

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