【问题标题】:How did anonymous function implements the trait?匿名函数是如何实现这个特征的?
【发布时间】:2017-02-12 22:03:14
【问题描述】:

让我们看看 scala REPL 中的代码: 首先,我定义了一个特征:

trait Service{
  def invoke(name:String):String
}

然后我定义了一个匿名函数:

def serviceImpl:Service = (name)=> s"Your name is $name"

效果很好。

serviceImpl 方法返回一个匿名函数 --- "(name)=> s"Your name is $name"" 只是 Function2[String, String] 特征的一个实例。

但如上所述,匿名函数如何实现 Service trait?

以及 scala 是如何转换的?

【问题讨论】:

  • 之所以有效,是因为结合了基于反射的鸭子类型 + java lambda 的契约。
  • 提示:除非您使用 Scala 2.12.x,否则这无法正常工作

标签: scala traits


【解决方案1】:

这是 2.12 发行说明中描述的新功能:http://www.scala-lang.org/news/2.12.0#lambda-syntax-for-sam-types

除了标准库中的 FunctionN 类型之外,Scala 2.12 类型检查器还接受函数文字作为任何单一抽象方法 (SAM) 类型的有效表达式。这改善了使用 Scala 代码为 Java 8 编写的库的体验。这是一个使用 java.lang.Runnable 的 REPL 示例:

scala> val r: Runnable = () => println("Run!")
r: Runnable = $$Lambda$1073/754978432@7cf283e1
scala> r.run()
Run!

请注意,只有 lambda 表达式被转换为 SAM 类型实例,而不是 FunctionN 类型的任意表达式:

scala> val f = () => println("Faster!")
scala> val fasterRunnable: Runnable = f
<console>:12: error: type mismatch;
found   : () => Unit
required: Runnable

语言规范包含 SAM 转换要求的完整列表。

使用默认方法,Scala 的内置 FunctionN 特征被编译为 SAM 接口。这允许使用 Java 自己的 lambda 语法从 Java 创建 Scala 函数:

public class A {
  scala.Function1<String, String> f = s -> s.trim();
}

专门的函数类也是SAM接口,可以在包scala.runtime.java8中找到。

由于类型检查的改进,即使调用的方法被重载,也可以省略 lambda 表达式中的参数类型。有关详细信息,请参阅#5307。在以下示例中,编译器为 lambda 推断参数类型 Int:

scala> trait MyFun { def apply(x: Int): String }
scala> object T {
    |   def m(f: Int => String) = 0
    |   def m(f: MyFun) = 1
    | }
scala> T.m(x => x.toString)
res0: Int = 0

请注意,尽管这两种方法都适用,但重载解析会选择具有 Function1 参数类型的方法,如下文更详细说明。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-07
    • 1970-01-01
    • 2021-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多