2012-11-02 109 views
10

我是相當新的Scala和我有一個關於複製的情況下,類同時保留來自特徵數據的最佳方式問題。舉例來說,假設我有以下幾點:斯卡拉:複製case類與特質

trait Auditing { 

    var createTime: Timestamp = new Timestamp(System.currentTimeMillis) 
} 

case class User(val userName: String, val email: String) extends Auditing 

val user = User("Joe", "[email protected]") 

然後我想和一個參數的新副本改變:現在

val user2 = user.copy(email = "[email protected]") 

,在上面的例子中,屬性createTime沒有得到因爲它沒有在用戶案例類的構造函數中定義而被複制。所以我的問題是:假設移動createTime到構造函數是不是一種選擇,究竟是什麼讓用戶對象包括從特徵值的副本的最佳方式?

我正在使用Scala 2.9.1

在此先感謝! 喬

+0

沒有太多的選擇之前,你,你不是手動實現這樣會產生你想要的副本在'User'案件類的聲明的方法或使用Scala的2.10宏功能來自動執行。對於初學者來說,第二個選項絕對不是一件容易的事。 –

+1

@NikitaVolkov如果你願意爲我/我提供一個關於如何用宏來做的例子,那將是非常棒的。 –

+2

@mhs我加入俱樂部。我是宏中的新手,這就是爲什麼我沒有發佈它作爲答案。但[這是如何](http://stackoverflow.com/a/10397595/485115)我用'Toolbox' api解決了一個非常類似的任務。我們接受的答案是基於宏,但我認爲它不支持最新的Scala版本。 –

回答

6

您可以覆蓋與行爲的複製方法。

case class User(val userName: String, val email: String) extends Auditing 
{ 
    def copy(userName = this.userName, email = this.email) { 
    val copiedUser = User(userName, email) 
    copiedUser.createTime = createTime 
    copiedUser  
    } 
} 
3

雖然我看不到其他解決方案比魯本的,我不明白要求保持構造函數參數不變。這將是最自然的解決方案:

case class User(userName: String, email: String, 
    override val createTime:Timestamp = new Timestamp(System.currentTimeMillis)) 
     extends Auditing 

如果你不希望用戶能夠覆蓋createTime,你仍然可以使用:

case class User private (userName: String, email: String, 
    override val createTime:Timestamp) extends Auditing { 
    def this(userName: String, email: String) = 
    this(userName, email, new Timestamp(System.currentTimeMillis)) 
} 

唯一的缺點是,你需要由於主要構造函數現在是私有的,所以請寫new User("Joe", "[email protected]")

0

你可能會不使用的情況下類的更好。您可以輕鬆實現您自己需要的 功能。下面的代碼實現了你想要的,一個構造函數沒有新的複製方法,隱藏了原來的構造,並創建一個提取,這樣就可以在case語句使用的用戶。

class User private(val userName: String, 
        val email: String, 
        val timeStamp: Timestamp = 
        new Timestamp(System.currentTimeMillis)) { 

    def copy(uName: String = userName, 
      eMail: String = email) = 
    new User(uName, eMail, timeStamp) 
} 

object User { 
    def apply(userName: String, email: String) = 
    new User(userName, email) 

    def unapply(u: User) = Some((u.userName, u.email, u.timeStamp)) 
}