我有一些类型为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点,所以我将在早上再检查一遍。
您可以使用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)
你明明需要锯子却想用锤子。您应该为此创建一个新类,并为每个类型创建一个字段。
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}
}
新手经常会为了一些疯狂的目的而使用集合。仅仅因为集合保存数据,并不意味着任何时候都需要一个集合来保存数据。在你决定你要用什么之前,你需要先考虑你的需求是什么,而不是相反,如果你采用这种方法,你将在你的编程生涯中使用SO。