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

带有编译器推断的隐式转换的

  • :1+"foo"
  • 带有显式调用的隐式转换的
  • :any2stringadd(1)+"foo"

  • 有没有办法在宏中区分这两个?

    最佳答案

    首先,1 + "foo"的情况将很棘手,因为那里实际上没有发生任何隐式转换:Int本身为really, truly does have this + method(unfortunately)。

    因此,如果这是您的用例,那么您会很不走运,但是可以更一般地执行您所描述的事情。我将在下面的示例中假设以下设置:

    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中可用。

    您可以在2.10中使用普通的旧def宏来获得所需的内容,但这有点麻烦:
    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子节点的位置是否在同一列中,这表明方法调用在其中没有显式存在。来源。

    关于scala - 如何区分编译器推断的隐式转换和显式调用的隐式转换?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15508660/

    10-09 20:53