Any to Function的隐式def将apply方法添加到类中

时间:2011-01-20 12:33:23

标签: scala

看看以下内容,看看你是否能够理解它:

Welcome to Scala version 2.8.1.final (Java HotSpot(TM) Client VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.

scala> class A
defined class A

scala> val a = new A
a: A = A@1643e4b

scala> a.apply("foo")
<console>:8: error: value apply is not a member of A
       a.apply("foo")
         ^

到此为止看起来完全正常。但后来我们添加了隐式转换。

scala> implicit def anyToFunc(any: Any) = { x: String => "bar" }
anyToFunc: (any: Any)(String) => java.lang.String

scala> a.apply("foo")
res1: java.lang.String = bar

突然A有一个apply方法接受一个与隐式返回的函数相同类型的参数!

让我们再检查一下:

scala> class B { override def toString = "an instance of class B" }
defined class B

scala> implicit def anyToFunc(any: Any) = { x: String =>
     | println("any is " + any.toString)
     | println("x is " + x)
     | "bar" }
anyToFunc: (any: Any)(String) => java.lang.String

scala> val b = new B
b: B = an instance of class B

scala> b.apply("test")
any is an instance of class B
x is test
res8: java.lang.String = bar

这是一个“隐藏的功能”吗?如果是这样,它的用途是什么?

3 个答案:

答案 0 :(得分:5)

您正在apply类型的对象上调用AA没有apply方法。但是,A可以隐式转换为Function[String, String],它有apply方法。因此,应用了隐式转换,并在转换后的对象上调用apply

这个功能没有任何魔力或隐藏。如果一个对象没有你正在调用它的方法,但是可以隐式转换为一个对象,那么它将被转换。这正是隐式转换的用途。

答案 1 :(得分:3)

在scala中创建的任何函数都将转换为使用apply方法的类。然后调用apply的简写就省略了。

class A{
    val a = (x:String) => x * 2
}
编译它,看看有两个文件,A.classA$$anonfun$1.class。使用javap检查类文件,你会看到
Compiled from "Fun.scala"
public final class A$$anonfun$1 extends scala.runtime.AbstractFunction1 implements java.io.Serializable{
    public static final long serialVersionUID;
    public static {};
    public final java.lang.String apply(java.lang.String);
    public final java.lang.Object apply(java.lang.Object);
    public A$$anonfun$1(A);
}
重要的一行是public final java.lang.String apply(java.lang.String);。这可以通过a("string")a.apply("string")进行调用。

是的,您可以使用implicit def将任何内容转换为函数,但它没有多大意义。它通常用于不同的情况:pimp my library

答案 2 :(得分:1)

隐式定义和apply方法的预期行为并不是隐藏的功能。关键的是,apply方法是一种特殊的方法,在将参数直接传递给对象时会被调用。因此,在您的示例中,您执行以下操作:

b.apply("Test")

这相当于b("test")Function定义了apply,因此我们可以做很好的事情,如:

val addOne = (b : Int) => b + 1
addOne(10)

因此,当您尝试在B的实例上调用apply时,编译器首先查看B是否有方法应用,然后查看B的超类是否有方法apply,然后查找具有方法apply的内容。这是隐式定义的目的。由于Function1有一个apply方法,因此调用隐式转换并调用函数的apply方法。