【问题标题】:scala: Retrieve arguments used to construct class instance in an inheritable way?scala:检索用于以可继承方式构造类实例的参数?
【发布时间】:2011-05-22 04:10:25
【问题描述】:

在 scala 中,我遇到了一个基类/特征被很多子类扩展的情况。我将通过获取类的名称和用于实例化该类的参数来序列化一个子类的实例(为了以后重建它)。使用反射很容易获取类实例的名称,但我不确定如何以不需要我在每个子类中编写代码的方式获取实例的参数。这也适用于按名称调用的参数。这似乎很棘手,因为每个子类可能具有完全不同数量和类型的构造函数参数:

abstract class Base {
  // ideally implements some way of finding out the arguments used to construct this object
  def getArgs = {...}
}

class ChildA() // args would be a 0-tuple

class ChildB(arg1: Int) // getArgs would be a 1-tuple of arg1

class ChildC(arg1: Double, arg2: Boolean) // args would be a 2-tuple of (arg1, arg2)

// etc... 

我想要避免的是让每个类都实现像“getArgs”这样的方法,并且只返回一个复制构造函数参数的元组。有什么办法吗?

我意识到另一种方法是使用某种拦截器来创建对象,但我不知道如何在不必为每个子类编写样板代码的情况下做到这一点。

编辑:案例类方法很优雅,但在我的情况下不适合,因为我们必须能够允许具体子类扩展其他具体子类。

【问题讨论】:

    标签: scala reflection


    【解决方案1】:

    如果您的目标是避免在每个子类中编写代码来捕获参数,并且所有子类都在一个平面层次结构中,直接从 Base 继承而不是从彼此继承,您应该考虑将它们声明为 case class改为es。然后他们会自动扩展Product,您可以使用和productIterator 到例如将所有 args 保存到 Array[Any](我正在使用 Array,因为这是您稍后反射性地调用这些类的构造函数时所需要的):

    scala> def toArray(p: Product) = p.productIterator.toArray
    toArray: (p: Product)Array[Any]
    
    scala> case class ChildA()
    defined class ChildA
    
    scala> toArray(ChildA())
    res0: Array[Any] = Array()
    
    scala> case class ChildB(arg1: Int)
    defined class ChildB
    
    scala> toArray(ChildB(42))
    res1: Array[Any] = Array(42)
    

    如果您希望toArray 只接受Base 的子类,则将其参数声明为Product with Base

    【讨论】:

    • @jean-philippe 不幸的是,一些子类扩展了其他子类。这会破坏这个计划吗?似乎案例类继承已被弃用。
    • @Heinrich 实际上,不幸的是,这破坏了这种技术。 (这就是我写“如果 [...] 子类处于扁平层次结构中”的原因。)
    • @Heinrich 层次结构不需要完全平坦,但非叶类不得是案例类。如果非叶类可以是抽象的(即您从不直接实例化它们),此解决方案仍然可以为您工作。
    • @Heinrich @Aaron 是对的。但请记住,productIterator 返回的值不包括抽象超类中的vals。
    • 是的,这几乎就是我在邮件列表中的建议。还要注意经常重复的格言,“每个类都应该是抽象的或最终的。”
    猜你喜欢
    • 1970-01-01
    • 2016-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 2015-05-06
    相关资源
    最近更新 更多