3

使用宏我想获得一个通用的解决方案来引用Symbol案例类数据树的字段和子字段。

受此要点的启发,我创建了以下骨架:

import language.experimental.macros
import reflect.runtime.universe._
import reflect.macros.Context

object SubRef {

  case class SubRef[ SourceT, TargetT ]( symbol : Symbol )

  implicit def functionToSubRef
    [ SourceT, TargetT ]
    ( f : SourceT => TargetT ) 
    : SubRef[ SourceT, TargetT ]
    = macro functionToSubRefMacro[ SourceT, TargetT ]

  def functionToSubRefMacro
    [ SourceT : c.WeakTypeTag, TargetT : c.WeakTypeTag ]
    ( c : Context )
    ( f : c.Expr[ SourceT => TargetT ] )
    : c.Expr[ SubRef[ SourceT, TargetT ] ]
    = ???

}

我希望这个解决方案能像这样工作:

case class A( b : B )
case class B( c : Int )

val ref : SubRef[ A, Int ] = _.b.c

如果传入函数,宏转换应该失败:

  • 不是单一的表达
  • 不返回符号的值,它是源符号的子字段,即targetSymbol.owner[.owner...] == sourceSymbol

缺少的宏实现应该是什么?

4

1 回答 1

2

除了 Simon 指出的你的符号在 2.10 中不起作用之外,编写这个宏应该很容易。看起来您已经知道如何执行验证,所以我将省略这部分。

这里真正的挑战是将编译时反射工件 ( c.universe.Symbol) 转换为运行时反射工件 ( ru.Symbol)。这可以通过物化来完成。已经有c.reifyTreeand c.reifyType,它对树和类型执行此操作,但c.reifySymbol尚不存在。

幸运的是,符号具体化应该很容易实现。只需将您的符号包装在一个标识中,即 write Ident(sym),然后调用c.reifyTree结果。然后在运行时,您只需从包装树中提取一个符号即可。

PS 现在我没有时间编写完成所有这些事情的代码。如果你们中的任何人实现宏并发布代码,我很乐意删除我的答案并为你投票:)

于 2013-03-12T10:27:59.100 回答