Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 将对象方法提升到类中_Scala_Macros - Fatal编程技术网

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)