斯卡拉 - 使用参数化类型参数化类型
问题描述:
里面我试图编译下面的代码:斯卡拉 - 使用参数化类型参数化类型
case class Settings(settingsList:List[Setting])
abstract class Setting[T](name:String, value:T)
但是编译器会抱怨:
Error:(9, 54) class Setting takes type parameters
case class Settings(settingsList:List[Setting])
^
,但相应的Java代码编译sucesfully:
public class Settings {
List<Setting> settingsList;
}
abstract class Setting<T> {
abstract T getValue();
abstract String getName();
}
斯卡拉有什么不同,它不会允许这样的行为?
答
Java已经被版本5基因化了,AFAIK向后兼容性可以省略类型参数。另外Java有使用站点的变化,通常使这些事情非常恼人的类型,而不是在Scala中使用站点差异。如果没有变化,你可以在Scala中使用一个存在类型List[Setting[_]]
,但可能会更好的使用权方差:
case class Settings(settingsList: List[Setting[Any]])
abstract class Setting[+A](name: String, value: A)
答
你只需要一个通配符类型:
case class Settings(settingsList:List[Setting[_]])
abstract class Setting[T](name:String, value:T)
这等同于Java代码。
答
相应的Java代码编译sucesfully
Setting
没有一个类型参数是原始类型。据Java documentation,
使用原始类型只允许作为让步的遗留代码的兼容性。强烈建议在将通用性引入到Java编程语言后编写的代码中使用原始类型。未来版本的Java编程语言可能会禁止使用原始类型。
用Java写的正确方法是
List<Setting<?>> settingsList;
和Scala相当于是List[Setting[_]]
,因为其他的答案说。
与方差混淆不一定是最好的主意。取决于Setting的实现细节,协方差可能没有意义,并且会限制设计。通配符似乎是要走的路。 –
@UlysseMizrahi它不是“搞乱”。我建议始终在有意义的情况下用差异注释类型。这就是基于子类型的系统的工作方式,而Scala更喜欢不可变的数据结构,因此这很有意义。在我无法确定的情况下,您可以使用存在(通配符)类型。 –
“这是一个基于子类型的系统工作的方式” - 这是不正确的,虽然协方差确实与不变性有关,但强制协方差意味着无法在方法参数中使用该类型(即使在不可变结构中也可能需要)。此外,方差在类型设计方面具有实际意义。我们是否需要设置[List [Int]]为设置[Iterable [Int]]?从设计的角度来看,这可能没有意义。 –