2014-02-18 43 views
1

我有以下類層次結構。斯卡拉層次分解和類型參數

sealed trait Foo { 
    val a: String 
} 
case class Bar1(a: String) extends Foo 
case class Bar2(a: String) extends Foo 

現在我想添加一個方便的方法來修改字段a。我需要在超類型Foo中使用此方法,並且我想使用case類的.copy方法(因爲實際上我有更多的字段並且使用構造函數很痛苦)。我第一次嘗試是使用模式匹配:

sealed trait Foo { 
    val a: String 
    def withField(b: String) = this match { 
    case b1: Bar1 => b1.copy(a = b) 
    case b2: Bar2 => b2.copy(a = b) 
    } 
} 

現在我也想我withField方法返回調用者,B1的實例類型,如果該方法是通過,如果該方法的B1類型,B2的實例調用如果這是我所知道的,則由B2Foo類型的實例調用。所以我想我自己可能可以參數化方法withField來達到這個目的。喜歡的東西:

sealed trait Foo { 
    val a: String 
    def withField[A <: Foo](b: String) = this match { 
    case b1: Bar1 => b1.copy(a = b) 
    case b2: Bar2 => b2.copy(a = b) 
    } 
} 

,但我不管理parametried withFieldthis類型。

我在這裏完全錯了嗎?我應該使用不同的模式,可能使用override修飾符?

非常感謝

回答

1

我會得到完全錯了嗎?我應該使用不同的模式,也許使用覆蓋修飾符?

是的。有兩種選擇:

sealed trait Foo { 
    val a: String 
    def withField(b: String): Foo 
} 

case class Bar1(a: String) extends Foo { 
    // return types are covariant, and Bar1 is subtype of Foo, 
    // so this is legal 
    def withField(b: String): Bar1 = ... 
} 

sealed trait Foo[ThisType <: Foo[ThisType]] { 
    val a: String 
    def withField(b: String): ThisType 
} 

case class Bar1(a: String) extends Foo[Bar1] { 
    def withField(b: String): Bar1 = ... 
} 

注二等比較複雜,如果你真的需要它,才應使用。

編輯回答基督徒的問題:

sealed trait Foo { 
    type ThisType <: Foo 
    def withField(b: String): ThisType = (this match { 
    case b1: Bar1 => b1.copy(a = b) 
    ... 
    }).asInstanceOf[ThisType] 
} 

case class Bar1(a: String) extends Foo { 
    type ThisType = Bar1 
} 

我不喜歡它:它需要一個演員,真正使用它需要依賴的方法類型,我不會感到驚訝,如果它打破了練習(例如因爲編譯器不能證明foo.ThisTypefoo.withField("a").ThisType是相同的)。

+0

還有一個問題需要注意:是否可以在字段中實現字段並返回正確類型(如Benoit試圖這樣做)? – Christian

+0

@Christian請參閱編輯。我不會使用它,除非出於某種原因絕對需要。 –

+0

是的,我認爲第二種方法太複雜了。好,所以我猜如果我想返回Bar1和Bar2的實例,我不能在父類中抽象'withField' –