Scala 将对象方法提升到类中
我想知道是否有一种方法可以自动从伴生对象提升静态方法,这样您就可以通过实例引用它们。比如:Scala 将对象方法提升到类中,scala,macros,Scala,Macros,我想知道是否有一种方法可以自动从伴生对象提升静态方法,这样您就可以通过实例引用它们。比如: object Foo { def bar = 5 } case class Foo() val f = Foo() f.bar 在删除实例参数的同时,自动提升需要类实例的对象方法的额外好处。(假设此) 如果您愿意接受一个编译器插件(希望下一个版本的编译器会附带该插件),那么您可以制作一个注释来完成所有您想要的功能。具体而言(我认为这就是你想要的): 将自动将需要类的实例作为其第一个arg的对象方
object Foo {
def bar = 5
}
case class Foo()
val f = Foo()
f.bar
在删除实例参数的同时,自动提升需要类实例的对象方法的额外好处。(假设此)
如果您愿意接受一个编译器插件(希望下一个版本的编译器会附带该插件),那么您可以制作一个注释来完成所有您想要的功能。具体而言(我认为这就是你想要的):
- 将自动将需要类的实例作为其第一个arg的对象方法提升到类方法中(第一个arg=
)this
- 将其余的对象方法提升为类方法(忽略此)
macros.scala
中,然后在Test.scala
-sbt compile
中进行实验。其他一切都由scala负责)
从根本上说,您所做的一切都是使用AST,并使其变得非常简单。有了上面的代码,我可以运行下面的代码,并获得Bar(3)
和3
的打印输出
object Main extends App {
val t = Bar(1)
println(t.inc())
println(t.two)
}
object Bar {
def inc(b: Bar) = {
val Bar(i) = b; Bar(i+2)
}
def two() = 3
}
@liftFromObject
case class Bar(i: Int)
请注意,由于这只是AST级别的操作,对于Scala以不同方式声明相同内容的不同语法来说,可能有点脆弱
import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros._
class liftFromObject extends StaticAnnotation {
def macroTransform(annottees: Any*) = macro liftFromObjectMacro.impl
}
object liftFromObjectMacro {
def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
annottees.map(_.tree) match {
case List(q"case class $cla(..$fields) extends ..$classBases { ..$classBody }"
,q"object $obj extends ..$objectBases { ..$objectBody }") =>
/* filter out from the object the functions we want to have in the class */
val newMethods = objectBody collect {
/* functions whose first arg indicates they are methods */
case q"def $name($arg: $t, ..$args) = { ..$body }"
if t.toString == cla.toString =>
q"def $name(..$args) = { val $arg = this; ..$body }"
/* other functions */
case func@q"def $name(..$args) = { ..$body }" => func
}
/* return the modified class and companion object */
c.Expr(q"""
case class $cla(..$fields) extends ..$classBases {
..$classBody;
..$newMethods
}
object $obj extends ..$objectBases { ..$objectBody }
""")
case _ => c.abort(c.enclosingPosition, "Invalid annottee")
}
}
}
object Main extends App {
val t = Bar(1)
println(t.inc())
println(t.two)
}
object Bar {
def inc(b: Bar) = {
val Bar(i) = b; Bar(i+2)
}
def two() = 3
}
@liftFromObject
case class Bar(i: Int)