Scala 宏 - 使用 `c.prefix` 推断隐式值 [英] Scala macro - Infer implicit value using `c.prefix`
问题描述
c.inferImplicitValue
推断调用站点范围内的隐式值.是否可以使用 c.prefix
范围推断隐式?
c.inferImplicitValue
infers implicit values in the call site scope. Is it possible to infer implicits using the c.prefix
scope?
这不是有效的代码,但表达了我的需要:
This is not valid code, but expresses what I need:
c.prefix.inferImplicitValue
我目前为此目的使用了一个简单的实现[1],但它有一些限制,例如不能从 def
推断隐式值和检测重复/模糊的隐式值.
I'm currently using a naive implementation for this purpose[1], but it has some limitations like not inferring implicit values from def
s and detecting duplicated/ambiguous implicit values.
推荐答案
简单地生成一个具有适当(本地)导入的块,然后调用 implicitly
就可以了:
Simply generating a block with an appropriate (local) import followed by a call to implicitly
does the trick:
q"""{import ${c.prefix}._; _root_.scala.Predef.implicitly[$T] }
其中 T
是 Type
的一个实例,表示要查找的隐式值的类型.
Where T
is an instance of Type
representing the type of the implicit value to lookup.
要检查隐式查找是否真的成功,您可以使用 silent=true
调用 Context.typeCheck
并检查结果树是否为空.
To check if the implicit lookup actually succeeded, you can call Context.typeCheck
with silent=true
and check if the resulting tree is empty or not.
作为说明,这里有一个示例,它实现了一个 infer
方法,如果在目标对象的成员中没有找到隐式,则返回 None
,否则包装结果是 Some
.
As an illustration, here is an example that implements an infer
method returning None
if the implicit was not found in the members of the target object, and otherwise wraps the result in a 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)
这篇关于Scala 宏 - 使用 `c.prefix` 推断隐式值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!