斯卡拉 - 使用参数化类型参数化类型

问题描述:

里面我试图编译下面的代码:斯卡拉 - 使用参数化类型参数化类型

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

与方差混淆不一定是最好的主意。取决于Setting的实现细节,协方差可能没有意义,并且会限制设计。通配符似乎是要走的路。 –

+0

@UlysseMizrahi它不是“搞乱”。我建议始终在有意义的情况下用差异注释类型。这就是基于子类型的系统的工作方式,而Scala更喜欢不可变的数据结构,因此这很有意义。在我无法确定的情况下,您可以使用存在(通配符)类型。 –

+0

“这是一个基于子类型的系统工作的方式” - 这是不正确的,虽然协方差确实与不变性有关,但强制协方差意味着无法在方法参数中使用该类型(即使在不可变结构中也可能需要)。此外,方差在类型设计方面具有实际意义。我们是否需要设置[List [Int]]为设置[Iterable [Int]]?从设计的角度来看,这可能没有意义。 –

你只需要一个通配符类型:

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[_]],因为其他的答案说。