2015-07-10 39 views
1

我有一些类型的集合Collection[SuperType]。存储在这个集合中的几个值是子类型SuperType,我希望集合只允许自己包含每个子类型的一个实例(有点像集合,但不是)。从参数到返回类型,在类型层次结构中的斯卡拉类型多态性

我试图写一个函数,鉴于上述亚型之一的同伴对象时,可以返回同伴对象所属的类的第一个实例。

最初我与集尝试作为如下所示,但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

你能不能简单地重新定义equals方法返回如果两个实例都是相同的,则返回true,然后直接使用Set? –

+0

好主意,应该有效。不知道我对劫持equals方法的感觉如何。 – Iain

回答

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) 
+0

谢谢,很高兴我可以使用类型参数!我改变了'获取[T <:SuperType:ClassTag]:选项[SuperType]'到'def获得[T <:SuperType:ClassTag]:选项[T]'所以我可以访问可能没有定义的成员'SuperType'并且对于子类型是唯一的。 – Iain

+0

当然,这太好了!我已经更新了答案。 –

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} 

} 

通常新手尝试使用集合为疯狂的目的。仅仅因为一个集合包含数据,并不意味着您想要保存数据的任何时候都需要它。在决定要使用什么之前,你需要先思考你的需求是什么,而不是其他方式,如果采取这种方法,你将在剩下的编程生涯中继续工作。

+0

我应该在我的问题中明确说明这一点,但我无法明确地知道所有的子类型。如果某个图书馆的某个用户想要为自己的自定义子类型扩展超类型,该怎么办?所以我想用你的锯子,但锤子对我的用例更好。 – Iain