将Set [Class [A]]返回Set [Class [_]]

时间:2015-02-20 01:43:31

标签: scala

在Scala 2.10.4上,给出以下特征和案例类:

scala> trait Parent
defined trait Parent

scala> case class Girl() extends Parent
defined class Girl

scala> case class Boy() extends Parent
defined class Boy

我正在尝试定义一个方法f,该方法会生成Set[Class[A]],其中A的类型为A <: Parent

scala> def f[A <: Parent]: Set[Class[A]] = Set[Class[A]](classOf[Boy], classOf[Girl])
<console>:12: error: type mismatch;
 found   : Class[Boy](classOf[$Boy])
 required: Class[A]
       def f[A <: Parent]: Set[Class[A]] = Set[Class[A]](classOf[Boy], classOf[Girl])
                                                                ^
<console>:12: error: type mismatch;
 found   : Class[Girl](classOf[$Girl])
 required: Class[A]
       def f[A <: Parent]: Set[Class[A]] = Set[Class[A]](classOf[Boy], classOf[Girl])

但是,如果我使用,我可以使它工作,我认为是“通配符”:

scala> def g[A <: Parent]: Set[Class[_]] = Set[Class[_]](classOf[Boy], classOf[Girl])
g: [A <: Parent]=> Set[Class[_]]

它有效:

scala> g
res5: Set[Class[_]] = Set(class Boy, class Girl)

为什么第一种方法失败了,但第二种方法成功了?最后,在Class[_]的上述定义中使用g是否有任何风险(键入安全性)?

1 个答案:

答案 0 :(得分:2)

问题是Class[A]在其类型参数中是不变的。因此Class[Boy]不是Class[Parent]。如果您设置显式返回类型Set[Class[Parent]]

,编译器会向您发出警告
scala> def f[_ <: Parent]: Set[Class[Parent]] = Set(classOf[Boy], classOf[Girl])
<console>:24: error: type mismatch;
 found   : Class[Boy](classOf[$Boy])
 required: Class[Parent]
Note: Boy <: Parent, but Java-defined class Class is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: Parent`. (SLS 3.2.10)
       def f[_ <: Parent]: Set[Class[Parent]] = Set(classOf[Boy], classOf[Girl])

以下方法使用存在类型,这实际上意味着您不关心类型是什么。 _是完全未绑定的,类型参数A是多余的。

def g[A <: Parent]: Set[Class[_]] = Set[Class[_]](classOf[Boy], classOf[Girl])

你不妨写一下:

def g: Set[Class[_]] = Set[Class[_]](classOf[Boy], classOf[Girl])
  

最后,在上面的g定义中使用类[_]是否有任何风险(类型安全)?

此时类型安全几乎已经消失,因为_可以是任何东西。 BoyGirlParentAnyToaster,...

我认为你能想到的最好的就是留意警告并得到类似的东西:

def g: Set[Class[_ <: Parent]] = Set(classOf[Boy], classOf[Girl])

这至少可以确保Set的元素限定在Parent之上。正是你打算用它做什么,我不知道。