【问题标题】:Implementing '.clone' in Scala在 Scala 中实现“.clone”
【发布时间】:2012-10-23 14:01:47
【问题描述】:

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

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

这是我目前的尝试:

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(这个) ^

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

c。说abstract trait有什么好处吗?

最后,有没有更好的标准解决方案?

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

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

【问题讨论】:

  • 如果你克隆状态每个时间步那么为什么“可变状态是必须的”?只有当您不需要每次都需要进行克隆时,可变性才有效。

标签: scala


【解决方案1】:

特征不能定义构造函数(我认为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

【讨论】:

  • 谢谢! self 类型似乎不是必需的。
  • 没有必要,但会阻止您执行class Egg extends DeepCloneable[Potato] 之类的操作。
  • 太棒了 - 这对我帮助很大!将数据从文件解析到模板类并随后“深度”复制时遇到了类似的问题。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:
    • 一个。当您定义一个 类型参数A 时,它会在编译阶段之后被擦除

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

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

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

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

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

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

    【讨论】:

    • 好,明确的答案。特别感谢'a'的澄清。有道理。
    猜你喜欢
    • 2012-08-26
    • 2010-10-27
    • 2012-07-06
    • 1970-01-01
    • 1970-01-01
    • 2011-06-07
    • 1970-01-01
    • 2011-07-18
    • 2014-10-26
    相关资源
    最近更新 更多