2015-12-27 90 views
2

我想編寫一個採用嵌套類型的泛型類。外部類型(I)必須擴展Iterable,內部類型(M)可以是任何東西。Scala中的嵌套類型的類型推斷

這裏是我有例子:

// The outer type here is I and the inner type is M 
class GenericDistributor[I <: Iterable[M], M] { 
    def map(input: I): Unit = { 
    input.foreach(item => { 
     //do some stuff 
    }) 
    } 
} 

class IntegerGroup(id: Int, items: Set[Int]) extends Iterable[Int] { 
    override def iterator: Iterator[Int] = items.iterator 
} 

object IntegerGroupDistributor extends GenericDistributor[IntegerGroup, Int] 

val integerGroup = new IntegerGroup(1, Set(1,2,3)) 
IntegerGroupDistributor.map(integerGroup) 

的問題是,我必須明確地定義,我不想給GenericDistributor類內部M型。是否有一種方法讓Scala自動推斷給定外部類型的內部類型?

編輯

根據@Arioch的評論。我嘗試了鴨子類型,似乎解決了我的問題,但我仍然覺得應該有更好的方法。

class GenericDistributor[I <: {type M; def iterator: Iterator[M]}] { 
    def map(input: I): Unit = { 
    val it: Iterator[M] = input.iterator 
    it.foreach(println) 
    } 
} 

class IntegerGroup(id: Int, items: Set[Int]) extends Iterable[Int] { 
    type M = Int 
    override def iterator: Iterator[Int] = items.iterator 
} 

object IntegerGroupDistributor extends GenericDistributor[IntegerGroup] 
+1

https://dzone.com/articles/duck-typing-scala-structural? –

+0

鴨子類型似乎解決了我的問題,但仍然不確定如果我可以做到這一點,而不設置'type M = Int' – mehmetgunturkun

+0

你可以使用直接繼承嗎? 'class GenericDistributor [M] {def map(input:Iterable [M]):Unit = {input.foreach(item => {...' - 換句話說,在你的例子中你永遠不需要'I',你只需要'M'無處不在,爲什麼還要麻煩?///我猜scala的主要問題在於Iterable是一個特性,所以你可以像'class IntegerGroup(id:Int,items:Set [Int])擴展Iterable [Int] Iterable [Double] Iterable [String]' –

回答

2

如果您不需要使用I類型的任何自定義方法,你的外部類只需要在M參數。 Iterator[M]不需要單獨添加,因爲您已經擁有了從M中定義它的全部內容。

class GenericDistributor[M] { 
    type I = Iterable[M] 
    def map(input: I): Unit = { 
     input.foreach(item => { 
     //do some stuff 
     }) 
    } 
} 
+0

問題是我可能需要輸入 – mehmetgunturkun

+0

@mehmetgunturkun你需要「我」類型 - 明確命名的'Iterable',特定的固定你的類實現的許多其他Iterables的Iterable?或者你需要'類IntegerGroup'? –

+0

嘗試像這樣'class GenericGroup [T](id:T,items:Set [T])extends Iterable [T] {type MainIterableType = T;重寫def iterator:Iterator [T] = items。迭代器}' - 你的主要目標是修復許多可能的特定Iterable,所以Scala可以在呼叫站點選擇許多具體的主類型 –

2

如果你只想要一個單一的類型參數有兩種選擇:

(1)你不關心迭代器型國家

class GenericDistributor[I <: Iterable[_]] 

(2)使用隱式存儲內部類型

class GenericDistributor[I : IterableInfo] 
// or (equivalently) 
class GenericDistributor[I]()(implicit i: IterableInfo[I]) 

trait IterableInfo[I] { 
    type Element 
} 

object IterableInfo { 
    implicit def forIterable[I <: Iterable[M], M]: IterableInfo[I] { type Element = M } = ... 
} 

最後一個選項允許你在很多不同的w中形成代碼AYS。您可以將方法添加到IterableInfo,您可以添加type成員,您可以將Iterable的限制添加到I類型參數。

+0

看到'IterableInfo [I,M]'和'IterableInfo [ I]'和'IterableInfo'在相同的範圍內。那些獨立的類型或具有不同專業化程度的相同類型?如果是後者,爲什麼選項1引用「Iterable [_]」而不僅僅是「Iterable」? –

+0

下面的選項1,如果給定的類將同時實現'Iterable [Int]'和'Iterable [String',哪一個可以被Scala調用'map'?或者應該如何在呼叫現場指定它? –

+0

@ Arioch'The你完全正確的古怪。我修正了更新答案以反映我的(未經測試)代碼中的問題。 – EECOLOR