我想了解lambda和Kotlin。我创建了这个简单的例子
interface OnClickListener {
fun onClick(s: String)
}
class Button {
var clickListener: OnClickListener? = null
fun setOnClickListener(listener: OnClickListener?) {
clickListener = listener
}
fun click() {
clickListener?.onClick("hello")
}
}
fun main(args: Array<String>) {
val b = Button()
b.setOnClickListener(
object : OnClickListener {
override fun onClick(s: String) {
println(s)
}
}
)
/*
Variation 1
val l = {
s -> println(s)
}
b.clickListener = l*/
/*
Variation 2
b.setOnClickListener{
s -> println(s)
}
*/
/*
Variation 3
b.clickListener = {
s -> println(s)
}
*/
b.click()
}
因此,仅当我传递匿名对象时,以上代码才会编译。但是我想弄清楚如何使用lambda。
使用lambda编译的3个变体都没有。
我以为OnClickListener
是SAM,所以我应该很容易就能通过lambda
我在这里做什么错了?
答案 0 :(得分:3)
要使用lambda,您需要使用Java接口。
首先,创建一个Java文件并创建一个接口:
public interface OnClickListener {
void onClick(String s);
}
然后在您的main
中:
b.setOnClickListener(OnClickListener { s ->
println(s)
})
关于您的Button
班:
class Button {
var clickListener: OnClickListener? = null //You can use this too but there's another way as well.
//lateinit var clickListener: OnClickListener //Telling the compiler that you will initialize it later on.
fun setOnClickListener(listener: OnClickListener) { //removed redundant ? from the function signature.
clickListener = listener
}
fun click() {
clickListener?.onClick("hello") //Incase of lateinit, you don't need a '?' anymore
}
}
SAM转换仅在Java代码和Kotlin代码之间起作用。
编辑:由于在Kotlin中,您也可以将函数存储在变量中,这是我的另外两分钱,以另一种方式来实现它:
class Button {
lateinit var myFunction: (String) -> Unit
fun setOnClickListener(block : (String) -> Unit) {
myFunction = block //storing state of your 'listener'
}
fun onClick() = myFunction.invoke("Invoked from onClick function")
}
然后在您的main
中:
fun main() {
val button = Button()
button.setOnClickListener { s ->
println(s)
}
button.onClick()
}
答案 1 :(得分:1)
正如Taseer Ahmad指出的那样,由于Kotlin已经具有适当的函数类型,所以SAM转换仅适用于Java接口。当然,解决此问题的一种简单方法是简单地定义第二个使用函数类型的setOnClickListener
方法
class Button {
var clickListener: OnClickListener? = null
fun setOnClickListener(listener: OnClickListener?) {
clickListener = listener
}
inline fun setOnClickListener(crossinline listener: (String) -> Unit) {
setOnClickListener(object : OnClickListener {
override fun onClick(s: String) = listener(s)
})
}
fun click() {
clickListener?.onClick("hello")
}
}
然后,您可以编写b.setOnClickListener { println(it) }
。我总是习惯使用内联这样的方法,但这并不是必需的,因此您可以根据需要删除inline
和crossinline
。