Scala类型多态,从参数到返回类型,在类型层次结构中

时间:2015-07-10 01:03:30

标签: scala types

我有一些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点,所以我早上会再检查一下。

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}

}

新手通常会尝试将集合用于疯狂目的。仅仅因为一个集合保存数据,并不意味着你想要保存数据的任何时候你需要一个。在决定要使用什么之前,你需要首先考虑你的要求,而不是相反,如果采用这种方法,你将在编程生涯的剩余时间内接受这些要求。