在所有情况下都不强制键入别名参数边界

时间:2014-11-14 23:50:11

标签: scala generics types case-class

TL; DR:似乎类型别名的类型参数(例如type T[X<:Serializable])在引用为变量,参数和其他情况时不会强制执行它们的约束。但是,案例类会对其参数正确执行边界。

考虑用于表示泛型类型子集的类型别名。例如,让我们说我想要Serializable事物列表的类型:

scala> type SerializableList[T <: Serializable] = List[T]
defined type alias SerializableList

现在说我想要一个带有这些参数的案例类:

scala> case class NetworkDataCC(things: SerializableList[_])
<console>:9: error: type arguments [_$1] do not conform to type SerializableList's type parameter bounds [T <: Serializable]
   case class NetworkDataCC(things: SerializableList[_])

嗯,这不起作用。 Scala(恼人地)不带有类型的参数边界,但它很容易修复:

scala> case class NetworkDataCC(things: SerializableList[_ <: Serializable])
defined class NetworkDataCC

好的。看起来不错。现在,如果我只想要一个带有这些东西的常规类,但我再次忘记显式声明类型边界。我期待一个错误:

scala> class NetworkData(val things: SerializableList[_])
defined class NetworkData
哦,等等。没有错误......呵呵。

那么,现在我能做到这一点吗?

scala> new NetworkData(List(1))
res3: NetworkData = NetworkData@e344ad3
嗯,这似乎很破碎。案例类,当然可以正常工作(因为声明了限制):

scala> NetworkDataCC(List(1))
<console>:11: error: type mismatch;
 found   : Int(1)
 required: Serializable
              NetworkDataCC(List(1))

在我的项目中,我正在利用反射来生成关于我的类的一些元数据。非案例类的元数据显示things上缺少界限:

scala> classOf[NetworkData].getDeclaredFields()(0).getGenericType
res0: java.lang.reflect.Type = scala.collection.immutable.List<?>

案例类是正确的:

scala> classOf[NetworkDataCC].getDeclaredFields()(0).getGenericType
res1: java.lang.reflect.Type = scala.collection.immutable.List<? extends scala.Serializable>

我无法在scala编译器错误跟踪器中找到任何错误。我是否误解了应该如何使用这些界限?

1 个答案:

答案 0 :(得分:4)

默认情况下,Scala的下划线不等同于SerializableList[X forSome {type X}]

scala> def aa(a: SerializableList[_]) = a
aa: (a: SerializableList[_])List[Any]

scala> def aa(a: SerializableList[X forSome {type X}]) = a
<console>:11: error: type arguments [X forSome { type X }] do not conform to type SerializableList's type parameter bounds [T <: Serializable]
   def aa(a: SerializableList[X forSome {type X}]) = a
             ^
scala> class NetworkDataCC(things: SerializableList[X forSome {type X}])
<console>:11: error: type arguments [X forSome { type X }] do not conform to typ
e SerializableList's type parameter bounds [T <: Serializable]
   class NetworkDataCC(things: SerializableList[X forSome {type X}])

相当于

scala> def aa(a: SerializableList[X] forSome {type X} ) = a
aa: (a: SerializableList[_])List[Any]

所以这种“无限制”的行为很好。看看这个答案:https://stackoverflow.com/a/15204140/1809978

案例类似乎有其他类型限制(由this bug引起,影响unapply方法,为案例类自动生成。)

如果你想在case类中使用“unbounded”存在类型,只需明确指定高阶类型:

 scala> case class NetworkDataCC[SerializableList[_]](things: SerializableList[_])
 warning: there were 2 feature warning(s); re-run with -feature for details
 defined class NetworkDataCC

 scala> NetworkDataCC(List(1))
 res5: NetworkDataCC[List] = NetworkDataCC(List(1))

甚至:

 scala> type SLL = SerializableList[_]
 defined type alias SLL

 scala> case class NetworkDataDD(things: SLL)
 defined class NetworkDataDD

所以这绝对是一个错误,您可以使用语义上等效的类型别名来解决它(请参阅SI-8997