动态混合特征

Nik*_*kov 38 scala traits mixins case-class

有特点

trait Persisted {
  def id: Long
}
Run Code Online (Sandbox Code Playgroud)

如何实现一个接受任何case类实例的方法并返回其特征混合的副本?

该方法的签名如下:

def toPersisted[T](instance: T, id: Long): T with Persisted
Run Code Online (Sandbox Code Playgroud)

Eug*_*ako 32

这可以通过宏完成(从2.10.0-M3开始,它正式成为Scala的一部分).以下是您正在寻找的主要示例.

1)我的宏生成一个本地类,它继承自提供的case类和Persisted,就像new T with Persisted那样.然后它缓存其参数(以防止多次评估)并创建所创建的类的实例.

2)我怎么知道要生成什么树?我有一个简单的应用程序,parse.exe打印解析输入代码产生的AST.所以我只是调用parse class Person$Persisted1(first: String, last: String) extends Person(first, last) with Persisted,注意输出并在我的宏中重现它.parse.exe是一个包装器scalac -Xprint:parser -Yshow-trees -Ystop-after:parser.探索AST有不同的方法,请阅读"Scala 2.10中的元编程".

3)如果你提供-Ymacro-debug-litescalac的参数,宏扩展可以进行健全性检查.在这种情况下,所有扩展都将打印出来,您将能够更快地检测到codegen错误.

编辑.更新了2.10.0-M7的示例

  • 我同意,单独编译是不方便的.我会看到我能做些什么. (3认同)

Emi*_*l H 9

使用vanilla scala无法实现您想要的效果.问题是mixins如下:

scala> class Foo
defined class Foo

scala> trait Bar
defined trait Bar

scala> val fooWithBar = new Foo with Bar
fooWithBar: Foo with Bar = $anon$1@10ef717
Run Code Online (Sandbox Code Playgroud)

创建一个Foo with Bar混合,但它不是在运行时完成的.编译器只是生成一个新的匿名类:

scala> fooWithBar.getClass
res3: java.lang.Class[_ <: Foo] = class $anon$1
Run Code Online (Sandbox Code Playgroud)

请参阅Scala中的动态混合 - 是否可能?了解更多信息.