Scala 用抽象类型扩展case类
我有两个这样的案例课程:Scala 用抽象类型扩展case类,scala,traits,case-class,Scala,Traits,Case Class,我有两个这样的案例课程: case class Size(id: Long, size: Int) case class Title(id: Long, title: String) . . . 我有10个功能差不多的。我决定将它们结合在一个共同的特征下,这导致了如下结果: trait Property[T]{ val value: T } trait PropertyPair[T]{ val id: Long val prop: Property[T] } case
case class Size(id: Long, size: Int)
case class Title(id: Long, title: String)
.
.
.
我有10个功能差不多的。我决定将它们结合在一个共同的特征下,这导致了如下结果:
trait Property[T]{
val value: T
}
trait PropertyPair[T]{
val id: Long
val prop: Property[T]
}
case class Size(id: Long, prop: Property[Int]) extends PropertyPair[Int] {
def size: Int = prop.value
}
case class Title(id: Long, prop: Property[String]) extends PropertyPair[String] {
def title: String = prop.value
}
sealed trait AnyProperty {
val id: Long
type Prop
val prop: Prop
}
sealed abstract class Property[T](
val prop: T
) extends AnyProperty {
type Prop = T
}
虽然上面的代码块似乎是一个很好的解决方案,现在我可以在PropertyPair
trait下定义函数,但代码仍然有味道
[T]
标题
我需要写
Title(101L, Property("Title"))
而不是
Title(101L, "Title")
出于某种原因,我确信有一种比我提供的更优雅、更不容易出错的解决方案。您不需要两个级别,可以用
抽象类
替换trait
,以利用其构造函数:
sealed abstract class Property[T](val prop: T) {
val id: Long
}
case class Size(id: Long, size: Int) extends Property[Int](size)
case class Title(id: Long, title: String) extends Property[String](title)
每种情况都有一个id
值,这是属性
类所需要的,但是由于您希望它们对prop
有不同的名称,您可以将它们作为prop
值传递给属性
构造函数
然后它可以用作
val size = Size(101L, 42)
val title = Title(202L, "Foo")
这是一个简单的解决方案。对于更一般的情况,我建议您这样做:
trait Property[T]{
val value: T
}
trait PropertyPair[T]{
val id: Long
val prop: Property[T]
}
case class Size(id: Long, prop: Property[Int]) extends PropertyPair[Int] {
def size: Int = prop.value
}
case class Title(id: Long, prop: Property[String]) extends PropertyPair[String] {
def title: String = prop.value
}
sealed trait AnyProperty {
val id: Long
type Prop
val prop: Prop
}
sealed abstract class Property[T](
val prop: T
) extends AnyProperty {
type Prop = T
}
(其余都一样)
这种方法的优点是,您可以使用top trait来引用任何属性,例如
def foo[P <: AnyProperty](p: P): Long = p.id
foo(size) // 101L
你想从继承层次结构中得到什么?你这么做是因为你认识到一个相似性,还是因为它实际上给了你一些你目前没有/预计会出现的新用例的功能?它实际上是最后一个代码块中的一个标签符号吗?还有一个问题:如果buh方法放在属性类中,我们需要类型保护吗?非常有趣。我假设你也可以通过传递buh方法将AnyProperty数组映射到它们的prop值,对吗?@Martee可能只是输入错误,但为了避免混淆:它是投影(投影/选择,而不是保护)。答案是否定的,当在
属性
中时,您可以直接引用属性
类型成员。@JordanCutler返回类型会有问题。如果您执行List[AnyProperty](大小、标题).map(buh)
,您将获得List(42,“Foo”)
。但是列表
是一个同质集合,即所有元素都具有相同的类型,在这种情况下,它将被派生为任何
(Int和字符串
的最低公共超类型)。这对您来说可能很好,但是您不需要任何类型的投影,只需进行buh
returnany
。