【问题标题】:Can Scala macros be defined inside a class (as methods of that class)?Scala 宏可以在类中定义(作为该类的方法)吗?
【发布时间】:2016-07-11 09:48:51
【问题描述】:

我的 Scala 断言库需要 Scala 宏(reify、quasiquote、macro impl)。


我希望能够做到这一点:

object1.assertEquals(object2) // success: object1 = object2

或者像这样:

3.assertEquals(1 + 1) // failure: 1 + 1 /= 3 

可以在隐式类中定义 Scala 宏吗?

【问题讨论】:

  • 是的,def 宏只是一个方法调用。您在应用程序中看到的前缀看起来会有所不同。
  • @som-snytt - “您在应用程序中看到的前缀看起来会有所不同”是什么意思?
  • @som-snytt - 如果我希望将对象本身“this”传递到宏中,我是否只需执行 q"$this" 并将其用作树,就像另一个一样树?
  • Context.prefix 树不是 object1 而是 myimplicit(object1)。毫无疑问有更好的例子,但github.com/som-snytt/regextractor/blob/master/util/src/main/…

标签: scala macros scala-macros scala-quasiquotes reify


【解决方案1】:

//ed : 写包

package so

trait AssertEquals[T, V] {
  def assertEquals(t: T, v: V): Boolean
}

object AssertEquals {
  implicit def assertEquals[T, V]: AssertEquals[T, V] = macro impl[T, V]


  implicit class WithAssertEquals[T](t: T) {
    def assertEquals[V](v: V)(implicit assertEquals: AssertEquals[T, V]): Boolean = assertEquals.assertEquals(t, v)
  }

  def impl[T: c.WeakTypeTag, V: c.WeakTypeTag](c: Context) = {
    import c.universe._
    val _t = c.weakTypeOf[T]
    val _v = c.weakTypeOf[V]

    //edit 2 : use symbolOf instead typeOf
    q"""
      {
      new ${symbolOf[so.AssertEquals[_, _]]}[${_t},${_v}]{
        def assertEquals(t: ${_t}, v: ${_v}): Boolean = t == v
      }
      }
      """
  }
}

//测试

import AssertEquals.WithAssertEquals

assert(1.assertEquals(2) == false)
assert(2.assertEquals(2) == true)
assert("a".assertEquals("a") == true)
assert("a".assertEquals("b") == false)
assert("a".assertEquals(1) == false)

【讨论】:

  • 你的意思是包“so”还是包对象“so”?因为我创建了“so”包并将其放入其中,但它不起作用。
  • 未找到:类型 AssertEquals [错误] assert(1.assertEquals(2) == false)
  • 对不起,这里应该使用symbolOf 而不是typeOf
【解决方案2】:

实现必须在对象或宏包中,但由宏实现的方法可以在隐式类中。 注意val self = q"${c.prefix}.self" 是获取对隐式类包装的对象的引用所必需的。

import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context


object assertions {
  implicit class AssertEquals[T](val self: T) extends AnyVal {
    def assertEquals(other: T): Unit = macro AssertionMacros.assertEquals[T]
  }

  object AssertionMacros {
    def assertEquals[T](c: Context)(other: c.Tree): c.Tree = {
      import c.universe._
      val self = q"${c.prefix}.self"
      q"_root_.scala.Predef.assert($self == $other)"
    }
  }
}

用法:

scala> import assertions._
import assertions._

scala> "foo" assertEquals "foo"

scala> "foo" assertEquals "bar"
java.lang.AssertionError: assertion failed
  at scala.Predef$.assert(Predef.scala:151)
  ... 43 elided

【讨论】:

  • 这是一个更简洁的实现。我特别喜欢你如何明确地提到“自我”,所以宏感觉就像它属于类。最佳答案。
猜你喜欢
  • 2023-04-10
  • 2022-01-28
  • 1970-01-01
  • 2021-05-04
  • 1970-01-01
  • 2013-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多