我有一些Collection[SuperType]
类型的集合。存储在这个集合中的是几个SuperType
子类型的值,我希望集合只允许自己包含每个子类型的一个实例(有点像集合,但不是)。
我正在尝试编写一个函数,当给定上述子类型之一的伴随对象时,可以返回伴随对象所属的类的第一个实例。
最初我尝试使用如下所示的Set,但是T将遭受类型擦除,因此模式匹配将失败。然后我也意识到Set不适合这个任务,因为我只想在集合中出现每个子类型。
def get[T <: SuperType](target: T): Option[SuperType] =
collection.collectFirst({
case target: T => target
})
我的下一步,当前的方法是使用地图,其中键是伴侣对象,值是伴侣对象的类的实例。类型层次结构如下所示。
trait SuperType
trait SuperTypeValue
// Pretend this has some parameters
case class ExampleSubType extends SuperTypeValue
case object ExampleSubType extends SuperType {
// value for use in later example
val uniqueToObjectField: String = "hello"
}
val collection: Map[SuperType, SuperTypeValue] = // Some new map
def get(target: SuperType): Option[SuperTypeValue] =
collection.get(target)
以上效果很好。但是,我想保留用作参数的子类型,并将其用作返回类型。我相信函数的签名看起来像这样:
get[T <: SuperType](target: T): Option[T]
// So I could then do something like this
get(ExampleSubType) match {
case Some(exampleSubType) => exampleSubType.uniqueToObjectField
case _ => "nope"
}
这是否可能在scala中?如果是这样,怎么样?如果没有,这是否存在于其他语言中,它叫什么?
希望这个问题没有明显的问题,但是凌晨2点,所以我早上会再检查一下。
答案 0 :(得分:1)
您可以使用ClassTags
来绕过类型擦除。而不是使用伴随对象,可能更容易明确地提供通用参数:
import scala.reflect._
trait SuperType { val x: Int }
case class Foo(x: Int) extends SuperType
case class Bar(x: Int) extends SuperType
val collection = Set(Foo(1), Foo(2), Bar(3), Foo(4), Bar(5))
def get[T <: SuperType : ClassTag]: Option[T] = {
collection.collectFirst {
case target: T => target
}
}
然后你可以打电话:
get[Foo] //Foo(1)
get[Bar] //Bar(3)
答案 1 :(得分:0)
当你需要锯时,你正试图使用锤子。你应该为每个类型的字段创建一个新类。
class SomeClass{
a:TypeA
b:TypeB
c:TypeC
// if c extends b extends a maybe you want
// to prevent a TypeC being assigned to A I have no idea
// you can change these implementations to get the behavior you want
addA(a:TypeA){ this.a = a}
addB(b:TypeB){ this.b = b}
addC(c:TypeC){ this.c = c}
}
新手通常会尝试将集合用于疯狂目的。仅仅因为一个集合保存数据,并不意味着你想要保存数据的任何时候你需要一个。在决定要使用什么之前,你需要首先考虑你的要求,而不是相反,如果采用这种方法,你将在编程生涯的剩余时间内接受这些要求。