我有以下类层次结构。
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
如果方法是由B2
和Foo
类型的实例调用的话,如果这是我所知道的。所以我想我可能能够将方法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)
}
}
但我无法使用withField
类型对this
进行参数设置。
我在这里完全错了吗?我可以使用override
修饰符来使用不同的模式吗?
非常感谢
答案 0 :(得分:2)
我在这里完全错了吗?我应该使用不同的模式吗?可能使用覆盖修饰符?
是。有两种选择:
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
}
我不喜欢它:它需要一个强制转换,实际使用它会需要依赖的方法类型,如果它在实践中崩溃我也不会感到惊讶(例如因为编译器无法证明{{1} }和foo.ThisType
是一样的。)