2012-10-23 80 views
4

我想知道如何在Scala中使用.clone我自己的對象。在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) 
} 

一個。爲什麼上面沒有編譯。提供:

 
error: class type required but A found 
    def myClone= new A(this) 
       ^

b。是否有辦法在特徵中聲明拷貝構造函數(def this(o:A)),以便使用特徵的類將被顯示爲需要提供一個特徵。

c。說abstract trait有什麼好處嗎?

最後,有沒有更好的方法,所有這一切的標準解決方案?

我已經研究過Java克隆。似乎不是爲了這個。此外Scala copy不是 - 它只適用於case類,它們不應該有可變狀態。

感謝您的幫助和任何意見。

+2

如果你克隆狀態_every time step_那麼爲什麼「可變狀態是必須的」?只有當你不需要每次都創建一個克隆時,可變性纔是有效的。 –

回答

7

特徵不能定義構造函數(我不認爲abstract對特徵有任何影響)。

是否有任何理由需要使用複製構造函數而不是僅實現克隆方法?有可能不需要在類上聲明[A]類型,但我至少已經聲明瞭一個自我類型,因此編譯器將確保該類型與該類匹配。

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

+0

謝謝!看起來,自我類型不是必需的。 – akauppi

+2

沒有必要,但會阻止你像'class Egg extends DeepCloneable [Potato]'一樣進行類似的操作。 – Nick

3
  • 一個。當您在類型參數(如A)中定義後,在編譯階段後被清除。

    這意味着編譯器使用類型參數來檢查您是否使用了正確的類型,但生成的字節碼不會保留A的信息。

    這也意味着你不能在代碼中使用A作爲真實類,而只能作爲「類型引用」,因爲在運行時這些信息會丟失。

  • b & c。 特徵不能根據定義定義構造函數參數或輔助構造函數,它們也根據定義是抽象的。

    你可以做的是定義一個特徵體能夠順利通過的具體實施實例稱爲

一個替代的解決方案是定義一個Cloneable類型類。有關這方面的更多信息,您可以找到關於此主題的大量博客,但我沒有針對特定博客的建議。

scalaz有使用這種模式,也許你能找到靈感有巨大的一部分建:你可以看看OrderEqualShow得到它的要點。

+0

好,清楚的答案。特別感謝「a」的澄清。說得通。 – akauppi

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 = [email protected] 

scala> val y = x.copy 
y: Foo = [email protected] 

scala> x eq y 
res2: Boolean = false