簡體   English   中英

在未經驗證的情況下編寫代碼時,Scala宏不會編譯

[英]Scala macro does not compile when code is crafted without reify

我一直在研究復雜的編譯時反射,並遇到了使用AST手動制作Scala代碼的需求。 在進行實驗時,我注意到了一個奇怪的編譯錯誤,這對我來說真的沒有意義,因此我嘗試在測試項目中重現它。

我使用Scala 2.10.4

這是代碼:

Macro.scala:

object Macro {
  def reifyTestImpl(c: Context): c.Expr[OffsetDateTime] = {
    import c.universe._
    val expression = reify(OffsetDateTime.now())
    c.echo(c.enclosingPosition, "With reify: " + show(expression.tree))
    c.echo(c.enclosingPosition, "With reify (raw): " + showRaw(expression.tree))
    expression
  }

  def manualAstTestImpl(c: Context): c.Expr[OffsetDateTime] = {
    import c.universe._
    val odtSymbol = typeOf[OffsetDateTime].typeSymbol
    val now = newTermName("now")
    val expression = c.Expr(
      Apply(
        Select(Ident(odtSymbol), now),
        List()
      )
    )
    c.echo(c.enclosingPosition, "Manual:     " + show(expression.tree))
    c.echo(c.enclosingPosition, "Manual (raw):     " + showRaw(expression.tree))
    expression
  }

  def reifyTest = macro reifyTestImpl
  def manualAstTest = macro manualAstTestImpl
}

Tester.scala:

object Tester {
  def main(args: Array[String]): Unit = {
    println(Macro.reifyTest)
    println(Macro.manualAstTest)
  }
}

c.echo的輸出是:

With reify: OffsetDateTime.now()
With reify (raw): Apply(Select(Ident(java.time.OffsetDateTime), newTermName("now")), List())
Manual:     OffsetDateTime.now()
Manual (raw):     Apply(Select(Ident(java.time.OffsetDateTime), newTermName("now")), List())

我得到的編譯錯誤是value now is not a member of java.time.OffsetDateTime調用上的Macro.manualAstTest
正如回聲的輸出所暗示的那樣,這兩個表達式是相同的-一個有效(來自reify的表達式),另一個無效(由apply-select精心制作的表達式)。

兩者之間有什么區別?

設法找到罪魁禍首。
顯然, typeOf[OffsetDateTime].typeSymbol返回的符號與從Scala類返回的符號相同,即沒有其靜態成員。

添加.companionSymbol似乎返回的符號與從Scala對象返回的符號相同,即僅具有靜態成員(顧名思義...)

因此,以下更改使其起作用:

val odtSymbol = typeOf[OffsetDateTime].typeSymbol.companionSymbol

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM