Take a look at the following and see if you can make any sense of it:
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")
^
It looks completely normal up to here. But then we add an implicit conversion.
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
And suddenly A has a apply
method that accepts an argument of same type that the function that the 开发者_如何学Pythonimplicit returns takes!
Let's inspect it a little more:
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
Is this a "hidden feature"? If so, what are the uses for it?
You're calling apply
on an object of type A
. A
does not have an apply
method. However A
is implicitly convertible to Function[String, String]
, which does have an apply
method. Thus the implicit conversion is applied and apply
is called on the converted object.
There's nothing magic or hidden about this feature. If an object doesn't have the method you're calling on it, but is implicitly convertible to one that does, it will be converted. It's exactly what implicit conversions are for.
any function created in scala is converted to a class with apply method. Then the shorthand for calling apply is omitting it.
class A{
val a = (x:String) => x * 2
}
compile this and see, that there are two files created, A.class
and A$$anonfun$1.class
. Inspect the class file with javap and you'll see thisCompiled 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);
}
The important line is public final java.lang.String apply(java.lang.String);
. This is called either by a("string")
or a.apply("string")
.
Yes, you can convert anything into function with
implicit def
s, but it doesn't make much sense. It is usually used in different cases: pimp my libraryIt isn't so much a hidden feature as the expected behaviour of implicit definitions and the apply
method. Critically, the apply
method is a special method that gets invoked when you pass arguments directly to an object. So when, in your example, you do the following:
b.apply("Test")
This would be equivalent to b("test")
. Function
defines apply so we can do nice things like:
val addOne = (b : Int) => b + 1
addOne(10)
So, when you try to call apply on an instance of B
, the compiler first looks whether B
has a method apply, then looks whether a superclass of B
has a method apply, then looks for an implicit to something that has a method apply
. This is the purpose of implicit definitions. Since Function1
has an apply method, the implicit conversion is called and the function's apply method is also called.
精彩评论