如何区分编译器推断的隐式转换和显式调用的隐式转换? [英] How to distinguish compiler-inferred implicit conversion from explicitly invoked one?

查看:104
本文介绍了如何区分编译器推断的隐式转换和显式调用的隐式转换?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们想象一下将这两个等效表达式传递给Scala宏:

Let's imagine passing these two equivalent expressions to a Scala macro:

  • 具有编译器推断的隐式转换:1+"foo"
  • 具有显式调用的隐式转换:any2stringadd(1)+"foo"
  • with compiler-inferred implicit conversion: 1+"foo"
  • with explicitly invoked implicit conversion: any2stringadd(1)+"foo"

在宏中是否可以区分这两个?

Is there a way to distinguish between these two inside the macro?

推荐答案

首先,1 + "foo"情况将非常棘手,因为实际上并没有发生任何隐式转换:Int本身确实,确实有此+方法(不幸的是).

First of all, the 1 + "foo" case is going to be tricky because there isn't actually any implicit conversion happening there: Int itself really, truly does have this + method (unfortunately).

如果这是您的用例,那么您就不走运了,但是有可能做更一般的描述.我将在下面的示例中假设以下设置:

So you're out of luck if that's your use case, but it is possible to do what you're describing more generally. I'll assume the following setup in my examples below:

case class Foo(i: Int)
case class Bar(s: String)
implicit def foo2bar(foo: Foo) = Bar(foo.i.toString)

首先讲究优雅的方法:

object ConversionDetector {
  import scala.language.experimental.macros
  import scala.reflect.macros.Context

  def sniff[A](tree: _): Boolean = macro sniff_impl[A]
  def sniff_impl[A: c.WeakTypeTag](c: Context)(tree: c.Tree) = {
    // First we confirm that the code typechecks at all:
    c.typeCheck(tree, c.universe.weakTypeOf[A])

    // Now we try it without views:
    c.literal(
      c.typeCheck(tree, c.universe.weakTypeOf[A], true, true, false).isEmpty
    )
  }
}

根据需要工作:

scala> ConversionDetector.sniff[Bar](Foo(42))
res1: Boolean = true

scala> ConversionDetector.sniff[Bar](foo2bar(Foo(42)))
res2: Boolean = false

不幸的是,这需要无类型的宏,这些宏目前仅在 Macro Paradise .

Unfortunately this requires untyped macros, which are currently only available in Macro Paradise.

在2.10中,您可以使用普通的旧def宏来获得所需的内容,但这有点麻烦:

You can get what you want with plain old def macros in 2.10, but it's a bit of a hack:

object ConversionDetector {
  import scala.language.experimental.macros
  import scala.reflect.macros.Context

  def sniff[A](a: A) = macro sniff_impl[A]
  def sniff_impl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]) = {
    import c.universe._

    c.literal(
      a.tree.exists {
        case app @ Apply(fun, _) => app.pos.column == fun.pos.column
        case _ => false
      }
    )
  }
}

再次:

scala> ConversionDetector.sniff[Bar](Foo(42))
res1: Boolean = true

scala> ConversionDetector.sniff[Bar](foo2bar(Foo(42)))
res2: Boolean = false

诀窍是要在抽象语法树中查找可以看到函数应用程序的位置,然后检查Apply节点及其fun子节点的位置是否在同一列中,这表明该方法调用未明确显示在源中.

The trick is to look for places where we see function application in our abstract syntax tree, and then to check whether the positions of the Apply node and its fun child have the same column, which indicates that the method call isn't explicitly present in the source.

这篇关于如何区分编译器推断的隐式转换和显式调用的隐式转换?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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