代码之家  ›  专栏  ›  技术社区  ›  waterlooalex

scala:如何在超类上实现克隆方法,并在子类中使用它?

  •  6
  • waterlooalex  · 技术社区  · 15 年前

    我可能是走错了方向,但我想要一个这样的物体:

    class MyDataStructure {
      def myClone = {
        val clone = new MyDataStructure
        // do stuff to make clone the same as this
        ...
        clone
      }
    }
    
    class MyDataStructureExtended(val foo: String) extends MyDataStructure
    

    然后:

    val data = MyDataStructureExtended
    val dataClone = data.clone
    println(dataClone.foo)
    

    所以,问题是数据克隆的类型是mydatastructure,而不是我希望的那样扩展的mydatastructureextended。

    我考虑在超级类中添加一个T类型,子类可以指定它(例如,它本身),但这似乎不是很有希望。

    4 回复  |  直到 6 年前
        1
  •  4
  •   Mitch Blevins    15 年前

    假设您希望最小化子类中的仪式数量,下面是我的建议:

    class A extends Cloneable {
      protected[this] def myCloneImpl[T] = {
        val justLikeMe = this.clone
        // copy values and such.
        // Note that the Object.clone method already made a shallow copy, but you may want
        // to deepen the copy or do other operations.
        justLikeMe.asInstanceOf[T]
      }
      def myClone = myCloneImpl[A]
    }
    
    class B extends A {
      override def myClone = myCloneImpl[B]
    }
    

    通过扩展java.lang.cloneable并调用object.clone方法,可以确保运行时类型与要克隆的对象相同。静态类型是通过类型转换(asInstanceOf[t])强制的。您将需要重写每个子类中的myclone方法并指定类型,但它应该是一个单行程序。

        2
  •  5
  •   faran    15 年前

    正如您所建议的,抽象类型或泛型参数是您所需要的。您是否要求mydatastructure不是特征类或抽象类?下面将mydatastructure定义为抽象类,但也可以将其作为特征。

    abstract class MyDataStructure {
      type T
      def myClone: T
    }
    
    class MyDataStructureExtended(foo: String) extends MyDataStructure {
      type T = MyDataStructureExtended
      def myClone = new MyDataStructureExtended(foo)
    }
    

    scala解释器的结果表明,mydatastructureextended中定义的myclone方法是正确的类型。

    scala> val mde = new MyDataStructureExtended("foo")
    val mde = new MyDataStructureExtended("foo")
    mde: MyDataStructureExtended = MyDataStructureExtended@3ff5d699
    scala> val cloned = mde.myClone
    val cloned = mde.myClone
    cloned: MyDataStructureExtended = MyDataStructureExtended@2e1ed620
    

    您可能希望限制t,使其类型只能是mydatastructure子类的类型。

    abstract class MyDataStructure {
      type T <: MyDataStructure
      def myClone: T
    }
    

    我不知道您的要求,但我相信scala 2.8将具有一些很好的功能,可以使用case类和命名参数来使用copy方法克隆case类。

        3
  •  0
  •   David Winslow    15 年前

    很难说你是不是用这样一个模糊不清的问题描述做得对,但实际上做起来相当简单。您可以简单地覆盖 myclone 在里面 MyDataStructureExtended 以便返回更具体的类型。当您有一个更具体类型的变量时,您也可以使用更具体的克隆方法。

    描述不清楚的示例代码:

    class A {
      def getMe = this
    }
    
    class B extends A {
      override def getMe = this
      def isAnInstanceOfB = true
    }
    

    以及相应的repl会话:

    scala> val a = new A
    a: A = A@1a6eeab
    
    scala> val b = new B
    b: B = B@a36771
    
    scala> a.getMe
    res0: A = A@1a6eeab
    
    scala> a.getMe.isAnInstanceOfB
    <console>:7: error: value isAnInstanceOfB is not a member of A
           a.getMe.isAnInstanceOfB
               ^
    
    scala> b.isAnInstanceOfB      
    res2: Boolean = true
    
    scala> b.getMe.isAnInstanceOfB
    res3: Boolean = true
    
        4
  •  0
  •   NEELAMADHAB    6 年前

    我认为这可能是解决办法。这不是继承的,你可以做一些修改来实现你的目标。祝你好运。

    class CloneableClass extends scala.Cloneable {
       def myMethod: Unit = println("Inside "+this.getClass)
       override def clone(): CloneableClass =super.clone().asInstanceOf[this.type]
    }
    
    class CloneableDemo  {
      val cc = new CloneableClass
      val cc1 = cc.clone()
      cc1.myMethod
    }
    
    object CloneObject extends App {
      val cd = new CloneableDemo
    }