看看以下内容,看看你是否能够理解它:
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
这是一个“隐藏的功能”吗?如果是这样,它的用途是什么?
答案 0 :(得分:5)
您正在apply
类型的对象上调用A
。 A
没有apply
方法。但是,A
可以隐式转换为Function[String, String]
,它有apply
方法。因此,应用了隐式转换,并在转换后的对象上调用apply
。
这个功能没有任何魔力或隐藏。如果一个对象没有你正在调用它的方法,但是可以隐式转换为一个对象,那么它将被转换。这正是隐式转换的用途。
答案 1 :(得分:3)
在scala中创建的任何函数都将转换为使用apply方法的类。然后调用apply的简写就省略了。
class A{
val a = (x:String) => x * 2
}
编译它,看看有两个文件,A.class
和A$$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方法。