Confusing Scala Dynamic code snippet
I came across the following code snippet on the Scala mailing list:
scala> class DynamicImpl(x: AnyRef) extends开发者_如何学运维 Dynamic {
| def _select_(name: String): DynamicImpl = {
| new DynamicImpl(x.getClass.getMethod(name).invoke(x))
| }
| def _invoke_(name: String)(args: Any*) = {
| new DynamicImpl(x.getClass.getMethod(name, args.map(_.asInstanceOf[AnyRef].getClass) : _*).invoke(x, args.map(_.asInstanceOf[AnyRef]) : _*))
| }
| override def typed[T] = x.asInstanceOf[T]
| override def toString = "Dynamic(" + x.toString + ")"
| }
defined class DynamicImpl
scala>
scala> implicit def toDynamic(x: Any): Dynamic = new DynamicImpl(x.asInstanceOf[AnyRef])
toDynamic: (x: Any)Dynamic
scala> class Duck {
| def quack = "Quack!"
| }
defined class Duck
scala> class QuackingSwan {
| def quack = "Swack!"
| }
defined class QuackingSwan
scala> def makeQuack(d: Dynamic) {
| println(d.quack.typed[String])
| }
dynatype: d._select_("quack")
makeQuack: (d: Dynamic)Unit
scala> makeQuack(new Duck)
Quack!
scala> makeQuack(new QuackingSwan)
Swack!
scala> val s: Dynamic = "Hello, world!"
s: Dynamic = Dynamic(Hello, world!)
scala> s.toLowerCase
dynatype: line8$object.$iw.$iw.s._select_("toLowerCase")
res2: Dynamic = Dynamic(hello, world!)
scala> s.length
dynatype: line8$object.$iw.$iw.s._select_("length")
res3: Dynamic = Dynamic(13)
scala> s.isEmpty.typed[Boolean]
dynatype: line8$object.$iw.$iw.s._select_("isEmpty")
res4: Boolean = false
What's _select_
and _invoke_
here?
_select_
and _invoke_
behave like Ruby missing_method
. When any method is called on a dynamic instance which does not implement the method, _select_
or _invoke_
are called instead. Those two methods can be implemented as you wish.
In your example, they use reflection to call the an actual implementation of the x
member. For instance:
scala> val s: Dynamic = "Hello, world!"
s: Dynamic = Dynamic(Hello, world!)
scala> s.toLowerCase
dynatype: line8$object.$iw.$iw.s._select_("toLowerCase")
res2: Dynamic = Dynamic(hello, world!)
The method toLowerCase
is not defined in s
. So the method _select_
is called instead with argument "toLowerCase"
. The dynamic mechanism will then call x.toLowerCase
using reflection and wrap the result in a new dynamic instance.
_select_
is called for any method without arguments, while _invoke_
is called for any method with arguments.
精彩评论