c.inferImplicitValue推断出调用站点范围中的隐式值.是否可以使用c.prefix范围推断出implicits?
这不是有效的代码,但表达了我的需要:
c.prefix.inferImplicitValue
我目前正在为此目的使用一个天真的实现[1],但它有一些限制,例如不从defs推断隐含值并检测重复/模糊隐含值.
解决方法
只需生成一个具有适当(本地)导入的块,然后调用隐式执行操作:
q"""{import ${c.prefix}._; _root_.scala.Predef.implicitly[$T] }
其中T是Type的实例,表示要查找的隐式值的类型.
要检查隐式查找是否实际成功,可以使用silent = true调用Context.typeCheck并检查生成的树是否为空.
作为一个例子,这里是一个实现一个推断方法的例子,如果在目标对象的成员中找不到隐式,则返回None,否则将结果包装在Some中.
import scala.reflect.macros.Context import scala.language.experimental.macros def inferImplicitInPrefixContext[T:c.WeakTypeTag](c: Context): c.Tree = { import c.universe._ val T = weakTypeOf[T] c.typeCheck( q"""{ import ${c.prefix}._ _root_.scala.Predef.implicitly[$T] }""",silent = true ) } def infer_impl[T:c.WeakTypeTag](c: Context): c.Expr[Option[T]] = { import c.universe._ c.Expr[Option[T]]( inferImplicitInPrefixContext[T](c) match { case EmptyTree => q"_root_.scala.None" case tree => q"_root_.scala.Some($tree)" } ) } trait InferOp { def infer[T]: Option[T] = macro infer_impl[T] }
我们来测试一下:
object Foo extends InferOp { implicit val s = "hello" } Foo.infer[String] // res0: Some[String] = Some(hello) Foo.infer[Int] // res1: None.type = None implicit val lng: Long = 123L Foo.infer[Long] // res2: Some[Long] = Some(123)