我想创建一个生成特征实现的方法。例如:
trait Foo {
def a
def b(i:Int):String
}
object Processor {
def exec(instance: AnyRef, method: String, params: AnyRef*) = {
//whatever
}
}
class Bar {
def wrap[T] = {
// Here create a new instance of the implementing class, i.e. if T is Foo,
// generate a new FooImpl(this)
}
}
我想像这样动态生成FooImpl
类:
class FooImpl(val wrapped:AnyRef) extends Foo {
def a = Processor.exec(wrapped, "a")
def b(i:Int) = Processor.exec(wrapped, "b", i)
}
手动实现每个特性并不是我们想要的(很多样板文件)所以我希望能够在编译时生成Impl类。我在考虑对类进行注释,也许正在编写一个编译器插件,但也许有一种更简单的方法?任何指针都将受到赞赏。
答案 0 :(得分:3)
你可以编写一个宏(宏从2.10.0-M3开始正式成为Scala的一部分),类似于Mixing in a trait dynamically。不幸的是,现在我没有时间为您撰写示例,但可以在http://groups.google.com/group/scala-internals的邮件列表中提问。
答案 1 :(得分:2)
java.lang.reflect.Proxy
可以做一些非常接近你想要的事情:
import java.lang.reflect.{InvocationHandler, Method, Proxy}
class Bar {
def wrap[T : ClassManifest] : T = {
val theClass = classManifest[T].erasure.asInstanceOf[Class[T]]
theClass.cast(
Proxy.newProxyInstance(
theClass.getClassLoader(),
Array(theClass),
new InvocationHandler {
def invoke(target: AnyRef, method: Method, params: Array[AnyRef])
= Processor.exec(this, method.getName, params: _*)
}))
}
}
这样,您就无需生成FooImpl
。
一个限制是它只适用于没有实现方法的特征。更确切地说,如果在特征中实现了一个方法,则调用它仍将路由到处理器,并忽略该实现。
答案 2 :(得分:1)
您可以在ScalaMock中看到三种不同的方法。
ScalaMock 2(当前发行版,支持Scala 2.8.x和2.9.x)使用java.lang.reflect.Proxy
来支持动态类型的模拟和编译器插件来生成静态类型的模拟。
ScalaMock 3(目前作为Scala 2.10.x的preview release提供)使用宏来支持静态类型的模拟。
假设你可以使用Scala 2.10.x,我强烈推荐基于宏的方法而不是编译器插件。您当然可以使编译器插件工作(如ScalaMock演示),但这并不容易,宏是一种非常出色的方法。