在 Scala 中自动初始化对象
Automatically initialize object in Scala
如果您运行这个简单的代码,您将看到以下内容:
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)
}
}
如果您运行这个简单的代码,您将看到以下内容:
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)
}
}