是否可以在 Scala 中使用 Java 8 种风格的方法引用?

Is it possible to use a Java 8 style method references in Scala?

我正在用 Scala 开发 JavaFX8 应用程序,但我不知道如何将方法引用传递给事件处理程序。澄清一下,我没有使用 ScalaFX 库,而是直接在 JavaFX.

之上构建我的应用程序

这是相关的代码片段。

InputController.java(我在 Java 中写了这个测试 class 来隔离问题以仅使用方法参考)

public class InputController {
    public void handleFileSelection(ActionEvent actionEvent){
        //event handling code
    }

    public InputController() {
        //init controller
    }
}

有效 (Java)

InputController inputController = new InputController();
fileButton.setOnAction(inputController::handleFileSelection);

这行不通 (Scala)

val inputController = new InputController
fileButton.setOnAction(inputController::handleFileSelection)

这是编译器 (Scala 2.11.6) 的错误消息。

Error:(125, 45) missing arguments for method handleFileSelection in class Main;
follow this method with '_' if you want to treat it as a partially applied function
    fileButton.setOnAction(inputController::handleFileSelection)
                                            ^

如果我改用 Scala 2.12.0-M2,我会收到不同的错误消息。

Error:(125, 45) missing argument list for method handleFileSelection in class Main
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `handleFileSelection _` or `handleFileSelection(_)` instead of `handleFileSelection`.
    fileButton.setOnAction(inputController::handleFileSelection)
                                            ^

Scala 是否有一种本地方式可以利用 Java 8 中引入的方法引用?我知道使用 lambda 表达式的隐式转换方法,但我想知道是否有一种方法可以使用类似于 Java 8 的方法引用而无需使用 lambda decleration。

您应该传递应用一个类型参数的函数 ActionEvent:

val button = new Button()
val inputController = new InputController()

def handler(h: (ActionEvent => Unit)): EventHandler[ActionEvent] =
  new EventHandler[ActionEvent] {
    override def handle(event: ActionEvent): Unit = h(event)
  }

button.setOnAction(handler(inputController.handleFileSelection))

inputController::handleFileSelection 是 Java 语法,它在 Scala 中不受支持或不需要,因为它已经有了像这样的 lambda 的简短语法:inputController.handleFileSelection _inputController.handleFileSelection(_)inputController.handleFileSelection 也可以,具体取决于上下文)。

但是,在 Java 中,当需要任何 SAM(单一抽象方法)接口时,您可以使用 lambda 和方法引用,而 EventHandler 就是这样一个接口。在 2.11 版之前的 Scala 中,这是完全不允许的,在 2.11 中,实验性支持将 lambdas 与 SAM 接口一起使用,必须使用 -Xexperimental scalac 标志启用,并且从 2.12 开始完全支持并且不' 需要启用。

如果你想要一个方法引用也将 class 实例作为参数,例如像 Java 中的 String::length,你可以做 (_:String).length 这是相当于(s:String) => s.length().

这些类型在 Java Function<String, Integer> 中,因此在 Scala 中 String => Int