2014-02-18 23 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' –