使用宏我想得到一个通用的解决方案,用于引用案例类数据树的Symbol
字段和子字段。
受this gist的启发,我创建了以下骨架:
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
缺少的宏实现应该是什么?
答案 0 :(得分:2)
除了西蒙指出你的符号在2.10中不起作用之外,编写这个宏应该很容易。看起来您已经知道如何执行验证,因此我将省略该部分。
这里真正的挑战是将编译时反射工件(c.universe.Symbol
)转换为运行时反射工件(ru.Symbol
)。这可以通过具体化来完成。已有c.reifyTree
和c.reifyType
,它们针对树和类型执行此操作,但c.reifySymbol
尚不存在。
幸运的是,符号验证应该很容易实现。只需将符号包装在Ident中,即写入Ident(sym)
,然后在结果上调用c.reifyTree
。然后在运行时,你只需从包装树中提取一个符号就可以了。
P.S。现在我没有时间编写完成所有这些事情的代码。如果你们中的任何人都实现了宏并发布了代码,我很乐意删除我的答案并向你们投票:)