Scala 宏 - 使用 `c.prefix` 推断隐式值 [英] Scala macro - Infer implicit value using `c.prefix`

查看:41
本文介绍了Scala 宏 - 使用 `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 defs and detecting duplicated/ambiguous implicit values.

[1] https://github.com/getquill/quill/blob/9a28d4e6c901d3fa07e7d5838e2f4c1f3c16732b/quill-core/src/main/scala/io/getquill/util/InferImplicitValueWithFallback.

推荐答案

简单地生成一个具有适当(本地)导入的块,然后调用 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] }

其中 TType 的一个实例,表示要查找的隐式值的类型.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆