4

我试图弄清楚如何.clone在 Scala 中创建自己的对象。

这是为了模拟,所以可变状态是必须的,由此产生了对克隆的全部需求。在将模拟时间提前之前,我将克隆一个完整的状态结构。

这是我目前的尝试:

abstract trait Cloneable[A] {
  // Seems we cannot declare the prototype of a copy constructor
  //protected def this(o: A)    // to be defined by the class itself

  def myClone= new A(this)
}

class S(var x: String) extends Cloneable[S] {
  def this(o:S)= this(o.x)    // for 'Cloneable'
  def toString= x
}

object TestX {
  val s1= new S("say, aaa")
  println( s1.myClone )
}

一种。为什么上面没有编译。给出:

错误:需要类类型但找到 A
  def myClone=new A(这个)
                   ^

湾。有没有办法在 trait 中声明复制构造函数 ( def this(o:A)),以便使用该 trait 的类显示需要提供一个。

C。说出来有什么好处abstract trait吗?

最后,对于这一切,有没有更好的标准解决方案?

我研究了 Java 克隆。似乎不是为了这个。Scalacopy也不是 - 它仅适用于案例类,它们不应该具有可变状态。

感谢您的帮助和任何意见。

4

3 回答 3

9

特征不能定义构造函数(我认为abstract对特征没有任何影响)。

是否有任何理由需要使用复制构造函数而不仅仅是实现克隆方法?可能不必在类上声明 [A] 类型,但我至少声明了一个 self 类型,因此编译器将确保该类型与类匹配。

trait DeepCloneable[A] { self: A =>
    def deepClone: A
}

class Egg(size: Int) extends DeepCloneable[Egg] {
    def deepClone = new Egg(size)
}

object Main extends App {
    val e = new Egg(3)
    println(e)
    println(e.deepClone)
}

http://ideone.com/CS9HTW

于 2012-10-23T14:16:29.177 回答
3
  • 一种。当您定义一个类型参数时,A它会在编译阶段后被删除。

    这意味着编译器使用类型参数来检查您是否使用了正确的类型,但生成的字节码不保留A.

    这也意味着您不能A在代码中用作真正的类,而只能用作“类型引用”,因为在运行时此信息会丢失。

  • b&c。trait不能通过定义定义构造函数参数或辅助构造函数,它们也是抽象的定义。

    您可以做的是定义一个特征体,该特征体在具体实现的实例化时被调用

一种替代解决方案是定义一个Cloneable typeclass。有关这方面的更多信息,您可以找到很多关于该主题的博客,但我没有具体的建议。

scalaz有很大一部分是使用这种模式构建的,也许你可以在那里找到灵感:你可以查看OrderEqualShow来了解它的要点。

于 2012-10-23T14:36:21.000 回答
3

它会建议一种基于类型类的方法。有了这个,也可以让现有的类是可克隆的:

class Foo(var x: Int)

trait Copyable[A] {
  def copy(a: A): A
}

implicit object FooCloneable extends Copyable[Foo] {
  def copy(foo: Foo) = new Foo(foo.x)
}

implicit def any2Copyable[A: Copyable](a: A) = new {
  def copy = implicitly[Copyable[A]].copy(a)
}


scala> val x = new Foo(2)
x: Foo = Foo@8d86328

scala> val y = x.copy
y: Foo = Foo@245e7588

scala> x eq y
res2: Boolean = false
于 2012-10-23T16:34:31.367 回答