如何在Kotlin中指定ActionListener?

如何在Kotlin中指定ActionListener?,kotlin,Kotlin,我想向Kotlin中的JButton添加ActionListener。在Java中,我只需编写以下内容: JPanel makeButtonPanel() { JPanel panel = new JPanel(new FlowLayout()); JButton dirButton = new JButton("Change directory"); dirButton.addActionListener(e -> chooseDirectory());

我想向Kotlin中的JButton添加ActionListener。在Java中,我只需编写以下内容:

JPanel makeButtonPanel() {
  JPanel panel = new JPanel(new FlowLayout());
  JButton dirButton = new JButton("Change directory");
  dirButton.addActionListener(e -> chooseDirectory());
  panel.add(dirButton)
  return panel;
}
但在科特林,事情并不是那么简单。我第一次尝试这个:

private fun makeButtonPanel() : JPanel {
  val panel = JPanel(FlowLayout())
  val dirButton = JButton("Choose")
  dirButton.addActionListener(e -> chooseDirectory()) // error message here
  // ...
}

private fun chooseDirectory() { ... }
但我收到了这个错误信息:

Type Mismatch
Required: ((ActionEvent!) -> Unit)!
Found: KFunction1<ActionEvent, Unit>
类型不匹配
必需:((ActionEvent!)->单元)!
找到:KFunction1

我明白了!这意味着这是一个具有不确定可空性的java方法,但这并不能帮助我理解如何编写它。我只想让它调用chooseddirectory()方法。一定有一个干净、简单的方法可以做到这一点,但我看不到。

好吧,我想出来了,而且非常简单。我只要省去括号,说

dirButton.addActionListener { chooseDirectory() }

我仍然不清楚什么时候应该用大括号而不是圆括号。

正如您所发现的,您需要使用大括号(
{
}

这是因为大括号是在Kotlin中定义lambda的必要部分。  (这与Java和Scala等语言不同,后者的必要部分是
->
=>
箭头。  这是因为在Kotlin中,如果有一个或没有参数,则箭头是可选的;如果有,则使用关键字。)

如果没有大括号,代码将调用
chooseddirectory()
函数,并尝试将其结果传递给
addActionListener()
——这显然是行不通的

大括号也足够了:它们被视为定义lambda,除非您给出了函数或方法的主体,或者在分支时给出了
if
/
。  (同样,这与大多数类似C/Java的语言不同。  在Kotlin中,如果只需要块作用域,则必须使用以下构造。)

至于括号,它们在这里是可选的。  如果需要,您可以将其包括在内:

dirButton.addActionListener({ chooseDirectory() })
但是Kotlin有一个如果一个函数的最后一个参数是一个函数,你可以在参数之后传递它:

dirButton.addActionListener(){ chooseDirectory() }
如果这会使paren为空,那么您可以完全忽略它们:

dirButton.addActionListener{ chooseDirectory() }
这是为了让函数看起来像新的语言语法。  例如,您可能满足以下功能:

with(someObject) {
    itsProperty = someValue
}
这只是一个非常普通的函数,在标准库中定义,并将函数作为其最后一个参数。  同样地:


还有一件事值得一提。  在Kotlin中,lambda是定义的一种方式,它是一类类型,可以像其他类型一样定义、传递和使用。  这与Java不同,Java传统上使用接口来实现这些目的——通常是使用单一抽象方法(“SAM接口”)的接口——在Java中,lambda只不过是定义此类接口匿名实现的语法糖

作为一种特殊情况,为了实现互操作性,Kotlin使用lambda来定义Java SAM接口(或者,自Kotlin 1.4以来,定义Kotlin)的实现,而不是函数


ActionListener
是一个Java SAM接口,这就是为什么您可以在这里使用lambda。

在kotlinI中使用大括号(
{}
)而不是普通括号(
()
)来表示lambda表达式。我将尝试在回答中解释这些问题。  (注释太多了!)大括号用于使用lambda语法定义它。您也可以执行
dirButton.addActionListener(::chooseddirectory)
来使用函数引用语法。还有其他方法可以指定它,比如使用匿名对象语法或命名函数语法。如果您只是调用另一个函数,那么函数引用语法通常更可取。否则,lambda通常会生成最干净的代码。
repeat(10) {
    // Some code to be run 10 times…
}