如果您运行这个简单的代码,您将看到以下内容:
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 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)
}
}
关于scala - 在 Scala 中自动初始化对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31777514/