【问题标题】:Automatically initialize object in Scala在 Scala 中自动初始化对象
【发布时间】:2015-08-04 22:14:06
【问题描述】:

如果您运行这个简单的代码,您将看到以下内容:

object A {
  println("from A")
  var x = 0
}

object B {
  println("from B")
  A.x = 1
}

object Test extends App {
  println(A.x)
}

// Result:
// from A
// 0

你可以猜到,scala 会延迟初始化对象。对象 B 未初始化,它的工作方式与预期不同。我的问题是:我可以使用哪些技巧来初始化对象 B 而无需访问它?我可以使用的第一个技巧是扩展具有某些特征的对象并使用反射来初始化扩展特定特征的对象。我认为更优雅的方法是使用宏注释来注释对象:

@init
object B {
  println("from B")
  A.x = 1
}

class init extends StaticAnnotation {
  def macroTransform(annottees: Any*) = macro init.impl
}

object init {
  def impl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._

    // what should i do here ?
  }
}

但我有点困惑。如何从宏impl方法中的注解对象调用方法(以初始化)?

【问题讨论】:

  • 生成的代码会去哪里?如果在object B 内部,在访问B 之前它仍然不会被调用;如果它创建了一个新的objectit 必须被外部代码访问;并且您不能在宏中的文件之外修改现有的objects。
  • “初始化对象 B 而不访问它” - 这是一个矛盾。访问和初始化是一回事。如果您在object Test 中写入B,您将初始化/访问它。但正如您所注意到的,从另一个对象的主体初始化其他对象是一种反模式。干脆不要这样做。

标签: scala annotations scala-macros


【解决方案1】:

我找到了解决办法:

用法:

object A {
  println("from A")
  var x = 0
}

@init
object B {
  println("from B")
  A.x = 1
}

@init
object C {
  println("from C")
  A.x = 2
}

object Test extends App {
  init()
  println(A.x)
}

输出:

from B
from A
from C
2

宏实现:

class init extends StaticAnnotation {
  def macroTransform(annottees: Any*) = macro init.impl
}

object init {
  private val objFullNames = new mutable.MutableList[String]()

  def impl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._

    annottees.map(_.tree).toList match {
      case (obj: ModuleDef) :: Nil =>
        objFullNames += c.typecheck(obj).symbol.fullName
      case _ =>
        c.error(c.enclosingPosition, "@init annotation supports only objects")
    }

    annottees.head
  }

  def apply() = macro runImpl

  def runImpl(c: whitebox.Context)(): c.Expr[Any] = {
    import c.universe._
    val expr = objFullNames.map(name => q"${c.parse(name)}.##").toList
    val res = q"{..$expr}"
    c.Expr(res)
  }
}

【讨论】:

    猜你喜欢
    • 2011-09-11
    • 2017-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-10
    相关资源
    最近更新 更多