Scala 如何对先前定义的对象使用quasiquotes

Scala 如何对先前定义的对象使用quasiquotes,scala,reflection,scala-macros,scala-reflect,scala-quasiquotes,Scala,Reflection,Scala Macros,Scala Reflect,Scala Quasiquotes,我刚开始研究scala编译时反射,scala官方指南向我介绍了Quasikotes 我仍在努力解决的一个概念是,如果我想为一个已经定义的对象生成AST,我应该如何使用Quasikotes(或具体化)。假设我有一个对象: 对象MyObject{ def method1()=“m1” } 为了得到一棵树,我知道我能做到 q”“{object MyObject{ def method1()=“m1” }} """ 然而,这样做会阻止我在我的作用域中实际定义对象(而且我还需要将它完全定义在一个字符串

我刚开始研究scala编译时反射,scala官方指南向我介绍了Quasikotes

我仍在努力解决的一个概念是,如果我想为一个已经定义的对象生成AST,我应该如何使用Quasikotes(或
具体化
)。假设我有一个对象:

对象MyObject{
def method1()=“m1”
}
为了得到一棵树,我知道我能做到

q”“{object MyObject{
def method1()=“m1”
}}
"""
然而,这样做会阻止我在我的作用域中实际定义对象(而且我还需要将它完全定义在一个字符串中,将所有代码安全性抛到窗外)

我想做的是得到那棵树是这样的:

对象MyObject{
def method1()=“m1”
}
q“$MyObject”//或q“{MyObject}”,我仍然不完全理解Scala指南中的表
我想定义对象,然后使用该定义对其执行一些检查(并在编译时抛出一些异常,如果需要的话),使用宏。要使用宏,就我所知,我需要建立树(或者至少是表达式)

我已经知道如何在运行时使用Scala反射进行检查,但我认为使用ASTs可能是一个好主意(在这个过程中,我会学到一些东西)。我觉得我误解了一些关于如何使用AST的基本概念,但是-似乎人们只能根据调用站点上声明的代码生成AST。我很困惑

我在这里误解了什么

quasikote

q"""{object MyObject {
  def method1() = "m1"
}}
"""

这些只是写树的方法

Block(
  List(
    ModuleDef(Modifiers(), TermName("MyObject"), 
      Template(
        List(Select(Ident(scala), TypeName("AnyRef"))), 
        noSelfType, 
        List(
          DefDef(Modifiers(), termNames.CONSTRUCTOR, List(), List(List()), TypeTree(), 
            Block(List(pendingSuperCall), Literal(Constant(())))
          ), 
          DefDef(Modifiers(), TermName("method1"), List(), List(List()), TypeTree(), 
            Literal(Constant("m1"))
          )
        )
      )
    )
  ),
  Literal(Constant(()))
)
同样可以从普通的
字符串

val str: String = 
  """object MyObject {
    |  def method1() = "m1"
    |}""".stripMargin

toolBox.parse(str)
有宏的编译时间和宏的运行时间。有主代码的编译时间和运行时。宏的运行时是主代码的编译时

MyObject
in

object MyObject {
  def method1() = "m1"
}
q"""{object MyObject {
  def method1() = "m1"
}}
"""
和中的
MyObject

object MyObject {
  def method1() = "m1"
}
q"""{object MyObject {
  def method1() = "m1"
}}
"""
存在于不同的环境中。前者存在于当前上下文中,后者存在于宏的调用站点上下文中

可以将树插入(拼接)到树中。不能将实际对象插入到树中。如果您有实际的对象(已编译的树),则将其插入树中为时已晚

当您看到有东西被插入到树中时,这意味着“某物”只是编写树的一种紧凑方式,即class
Liftable类型的实例

object MyObject {
  def method1() = "m1"
}

implicit val myObjectLiftable: Liftable[MyObject.type] = new Liftable[MyObject.type] {
  override def apply(value: MyObject.type): Tree =
    q"""
      object MyObject {
        def method1() = "m1"
      }"""
}

q"""
   class SomeClass {
     $MyObject
   }"""
我猜你的宏看起来像

def foo[A](a: A) = macro impl[A]

因此,您可以像
foo(MyObject)
foo[MyObject.type]
和inside那样调用它

def impl[A: c.WeakTypeTag](c: blackbox.Context)...

您可以访问[A]
的weakTypeOf,然后访问其符号。有了符号,你就可以有方法等的签名。

看,我已经阅读了全文,理解了一半,并且学会了如何应用其中任何一个:(是的,我也从来没能让宏注释起作用。这是什么样的检查?它们是否涉及方法签名之类的东西,而且它们总是在编译时知道的?它们只涉及方法签名。本质上,我有一个对象,我想确保它的方法中有一个特定的签名,尽管我不知道有多少是方法将会存在。当然,我可以声明一个trait并列出每个方法,但是,当添加一个新方法时,我需要声明该方法,并在trait上注册它,这是很糟糕的。目前,我正在使用运行时反射来检查类型,但错误只会在运行测试时出现。我想提高开发人员的体验通过在编译时立即抛出错误进行操作。@LucasLima您的问题听起来像是。如果您用实际问题(对象、检查等)创建一个问题会更好与。
有宏的编译时间和宏的运行时间。有主代码的编译时间和它的运行时间。宏的运行时间是主代码的编译时间。
这正是我理解中缺少的。你的回答完全消除了我的疑虑。谢谢。正如我在上面的评论中所说,我已经用运行时反射,但是,现在您已经解释过了,如果我可以通过宏在compiletime上使用运行时反射,这就解决了所有问题,所有的部分都在一起了。`我只需要把两端绑在一起。谢谢!