考慮以下基類和派生類Scala中:處理基類vs派生類字段名稱的習慣Scala方式?
abstract class Base(val x : String)
final class Derived(x : String) extends Base("Base's " + x)
{
override def toString = x
}
這裏,標識符派生類參數「x」的覆蓋的基類的領域中,所以調用的toString這樣的:
println(new Derived("string").toString)
返回Derived值並給出結果「string」。
因此對'x'參數的引用會提示編譯器自動在Derived上生成一個字段,該字段在對toString的調用中提供。這通常很方便,但會導致字段的複製(我現在將這個字段存儲在Base和Derived上),這可能是不可取的。爲了避免這種複製,我可以從「X」派生類參數重命名爲別的東西,比如「_x」:
abstract class Base(val x : String)
final class Derived(_x : String) extends Base("Base's " + _x)
{
override def toString = x
}
現在到ToString返回「基地的弦」,這是我想要的電話。不幸的是,現在的代碼看起來有點醜,並使用命名參數初始化類也變得不那麼優雅:
也有忘記給派生類初始化參數不同的名稱,並在不經意間提到的風險錯誤的字段(因爲Base類可能實際上持有不同的值而不受歡迎)。
有沒有更好的方法?
編輯1:爲了澄清,我真的只想要Base值;派生的對於初始化基類的字段來說似乎是必需的。該示例僅引用它們來說明隨後的問題。
編輯2:實際上,例如本來是清晰的,如果我用了瓦爾代替丘壑,因爲這凸顯與基類價值觀得到改變後的問題:
class Base(var x : Int) { def increment() { x = x + 1 } }
class Derived(x : Int) extends Base(x) { override def toString = x.toString }
val derived = new Derived(1)
println(derived.toString) // yields '1', as expected
derived.increment()
println(derived.toString) // still '1', probably unexpected
編輯3:如果派生類將以其他方式隱藏基類字段,那麼有辦法抑制自動字段生成可能會很好。看起來Scala編譯器實際上可能是爲你設計的,但是這當然違背了更接近標準的規則(Derived類'x')隱藏更遠的標識符(Base類' 'X')。這似乎是一個相當不錯的解決辦法是像修改「諾瓦爾」,也許是這樣的:
class Base(var x : Int) { def increment() { x = x + 1 } }
class Derived(noval x : Int) extends Base(x) { override def toString = x.toString }
val derived = new Derived(1)
println(derived.toString) // yields '1', as expected
derived.increment()
println(derived.toString) // still '2', as expected
我會提交一張增強票據,以抓取Edit2和Edit3案例併發出警告。這個問題不僅僅是用類構造函數,而且你也可以在子類中引入參數名稱。 – jsuereth
@jsuereth如果兩個字段的值可能不同(即,如果您不只是將構造函數參數傳遞給基類),那麼即使帶有「val」也會很好。我沒有看到從Derived內引用Base.x的方法(即使使用自引用註釋)。 –
如果x是一個val,那麼可以在Derived中引用super [Base] .x。否則,它不是一個真正的領域,只是'封閉在類的範圍內',所以它默默地被添加爲一個字段。我知道這個區別有點愚蠢,但圖像是將變量提升爲匿名函數構造函數的機制。 – jsuereth