匿名函数如何实现特征?

时间:2016-12-16 08:20:39

标签: scala traits

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

_view.Inherited.Radius+=10;

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

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

工作正常。

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

但如上所述,匿名函数如何实现服务特征?

以及scala如何转换?

1 个答案:

答案 0 :(得分:5)

这是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参数类型的方法,如下面更详细的说明。