2016-05-31 211 views
1

裏面我試圖編譯下面的代碼:斯卡拉 - 使用參數化類型參數化類型

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(); 
} 

斯卡拉有什麼不同,它不會允許這樣的行爲?

回答

1

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]]?從設計的角度來看,這可能沒有意義。 –

3

你只需要一個通配符類型:

case class Settings(settingsList:List[Setting[_]]) 
abstract class Setting[T](name:String, value:T) 

這等同於Java代碼。

0

相應的Java代碼編譯sucesfully

Setting沒有一個類型參數是原始類型。據Java documentation

使用原始類型只允許作爲讓步的遺留代碼的兼容性。強烈建議在將通用性引入到Java編程語言後編寫的代碼中使用原始類型。未來版本的Java編程語言可能會禁止使用原始類型。

用Java寫的正確方法是

List<Setting<?>> settingsList; 

和Scala相當於是List[Setting[_]],因爲其他的答案說。