在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
是否有任何风险(键入安全性)?
答案 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定义中使用类[_]是否有任何风险(类型安全)?
此时类型安全几乎已经消失,因为_
可以是任何东西。 Boy
,Girl
,Parent
,Any
,Toaster
,...
我认为你能想到的最好的就是留意警告并得到类似的东西:
def g: Set[Class[_ <: Parent]] = Set(classOf[Boy], classOf[Girl])
这至少可以确保Set
的元素限定在Parent
之上。正是你打算用它做什么,我不知道。