【问题标题】:Scala single method interface implementationScala单方法接口实现
【发布时间】:2014-04-02 18:46:27
【问题描述】:

Scala 是否有任何语法糖来替换以下代码:

val thread = new Thread(new Runnable {
   def run() {
     println("hello world")
   }    
})

类似的东西:

val thread = new Thread(() => println("hello world"))

如果特征/接口只需要一种方法来实现?如果没有,将来是否有机会在 Scala 中拥有此功能?它在处理 Java 类时特别有用。

我发现三年前问过一个类似的问题:Generically implementing a Java Single-Abstract-Method interface with a Scala closure? 答案说我们应该在 Scala 2.10 中拥有该功能。我一直在寻找 Single Abstract Method 关键字,但我没有找到任何东西。该功能发生了什么?

【问题讨论】:

  • 我有一个基于概念验证的小演示 ​​here。它可以很容易地变得更通用和更健壮,但你不会得到你所要求的简洁性。

标签: scala interface lambda syntactic-sugar traits


【解决方案1】:

Scala 从 2.11 开始对 SAM 提供实验性支持,标记为 -Xexperimental

Welcome to Scala version 2.11.0-RC3 (OpenJDK 64-Bit Server VM, Java 1.7.0_51).
Type in expressions to have them evaluated.
Type :help for more information.

scala> :set -Xexperimental

scala> val r: Runnable = () => println("hello world")
r: Runnable = $anonfun$1@7861ff33

scala> new Thread(r).run
hello world

编辑:从 2.11.5 开始,这也可以内联完成:

scala> new Thread(() => println("hello world")).run
hello world

预期类型的​​通常限制也适用:

  • 它必须定义一个抽象方法,
  • 其主要构造函数(如果有)必须是公共的、无参数的、未重载的,
  • 抽象方法必须采用单个参数列表,
  • 抽象方法必须是单态的。

根据 Adriaan 的 original commit,未来可能会取消其中一些限制,尤其是最后两个。

【讨论】:

  • 请注意问题已解决。
【解决方案2】:

使用 invokeDynamic 支持 SAM 类型,因为 scala-2.12 类似于 JDK-8,下面在 2.12.3 上进行了测试 - 可以在此处找到有关 SAM 的发行说明 - http://www.scala-lang.org/news/2.12.0/

object ThreadApp extends App {
  println("Main thread - begins")
  val runnable: Runnable = () => println("hello world - from first thread")

  val thread = new Thread(runnable)
  println("Main thread - spins first thread")
  thread.start()

  val thread2 = new Thread(() => println("hello world - from second thread"))
  println("Main thread - spins second thread")
  thread2.start
  thread.join()
  thread2.join()

  println("Main thread - end")
}

【讨论】:

    【解决方案3】:

    虽然以通用方式执行此操作肯定很复杂,但如果您发现您确实只需要对少数特定 Java 类型执行此操作,那么一些简单的隐式转换就可以很好地完成这项工作。例如:

    val thread = new Thread(() => println("hello world"))
    thread.start
    
    implicit def function0ToRunnable(f:() => Unit):Runnable = 
      new Runnable{def run() = f()}
    

    如果您的实际问题比您想象的更有限,有时尝试以通用且完全可重用的方式解决问题是错误的方法。

    【讨论】:

      猜你喜欢
      • 2020-04-06
      • 1970-01-01
      • 2019-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-05
      • 2014-04-12
      • 1970-01-01
      相关资源
      最近更新 更多