【问题标题】:Instantiate a class with Scala Macro or reflection使用 Scala 宏或反射实例化一个类
【发布时间】:2013-09-16 22:44:18
【问题描述】:

在我的 scala 代码中,我希望能够实例化一个新类。例如,假设我有以下代码:

class Foo { def foo=10 }
trait Bar { val bar=20 }

理想情况下,我希望能够执行以下操作:

def newInstance[A <: Foo] = { new A with Bar }
newInstance[Foo]

但是,这当然行不通。我尝试使用反射来实例化一个类,但似乎我只能实例化一个新类(而不是与特征混合)。我认为可以使用宏来完成这项工作,但我什至不确定从哪里开始。

我想要做的就像下面的 Ruby 代码:

class SomeClass
  def create
    self.class.new
  end
end

class Other < SomeClass
end

Other.new.create # <- this returns a new Other instance

有可能吗?

【问题讨论】:

    标签: scala reflection macros scala-macros


    【解决方案1】:

    使用宏:

    import scala.language.experimental.macros
    import scala.reflect.macros.Context
    
    object MacroExample {
      def newInstance[A <: Foo]: A with Bar = macro newInstance_impl[A]
    
      def newInstance_impl[A <: Foo](c: Context)(implicit A: c.WeakTypeTag[A]) = {
        import c.universe._
    
        c.Expr[A with Bar](q"new $A with Bar")
      }
    }
    

    这将按预期工作,如果您尝试实例化没有无参数构造函数的类,则会在编译时失败。

    为了清楚起见,我在这里使用了quasiquotes,但您可以手动构建树,但需要做更多的工作。不过,现在 quasiquotes 可作为 Scala 2.10 的插件使用,实际上并没有什么好的理由。

    【讨论】:

    • 是否有可能克服此解决方案的擦除问题,例如:“class NewClass[A] { MacroExample.newInstance[A] }”不起作用...
    • 其他,我没有找到复制“Ruby”行为的方法,即用 Other 扩展 SomeClass 并在子类中实例化“Other”类...
    • @MaurícioSzabo:关于你的第一个问题:问题并不完全是擦除——它是 A(即使有 &lt;: Foo 约束)不知道是一个类类型。如果您想要更好的错误消息,您可以检查 weakTypeOf[A].typeSymbol 是否为 ClassSymbol
    • @MaurícioSzabo:如果SomeClassOther 都是类,那么在Scala 中就无法继承它们(即使使用宏)。
    • 我知道没有办法从他们两个继承。我想要的是制作一个“类似克隆”的方法,就像我在 Ruby 中展示的那样:在超类上定义一个“克隆”方法,子类会自动理解它们需要返回子类,而不是超类(当然提供,该类实现了一个无参数构造函数)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-10
    • 1970-01-01
    • 2015-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多