2015-09-26 53 views
1

這實在是一個複雜的場景。頂點和邊被添加到圖中。一直希望增加可變數量的便利方法。任何我試圖讓後者api需求發生的方式,我會錯過類型擦除,或​​編譯器無法解析需要調用哪個重寫的方法。涉及的重載方法,類型限制使用和...類型擦除

/* 
* API definition 
*/ 
abstract class AbstractGraph[ID, Vertex <: AbstractVertex[ID], Edge <: AbstractEdge[ID]] { 

    def += (vertex: Vertex): AbstractGraph[ID, Vertex, Edge] 

    def += (edge: Edge): AbstractGraph[ID, Vertex, Edge] 

    def ++=(inputs: Addable*): AbstractGraph[ID, Vertex, Edge] = { 
    inputs.foreach(i => i match { 
     case v : AbstractVertex[ID] => this += v 
     case e : AbstractEdge[ID] => this += e 
    }) 
    this 
    } 
} 


abstract trait Addable 

/* 
* trait to be mixed in by user code for making their nodes graph friendly 
*/ 
abstract trait AbstractVertex[ID] extends Addable { 
    val id: ID 
} 

/* 
* trait to be mixed in by user code for making their edges graph friendly 
*/ 
abstract trait AbstractEdge[ID] extends Addable { 
    val id1: ID 
    val id2: ID 
} 

此意圖證明上述變化,失敗與以下:下面的代碼意圖通過一個失敗的變化表示

overloaded method value += with alternatives: 
(edge: Edge)org.canve.simpleGraph.AbstractGraph[ID,Vertex,Edge] <and> 
(vertex: Vertex)org.canve.simpleGraph.AbstractGraph[ID,Vertex,Edge] 
cannot be applied to (org.canve.simpleGraph.AbstractVertex[ID]) 
    case v : AbstractVertex[ID] => this += v 
            ^

overloaded method value += with alternatives: 
(edge: Edge)org.canve.simpleGraph.AbstractGraph[ID,Vertex,Edge] <and> (vertex: Vertex)org.canve.simpleGraph.AbstractGraph[ID,Vertex,Edge] 
cannot be applied to (org.canve.simpleGraph.AbstractEdge[ID]) 
    case e : AbstractEdge[ID] => this += e 
            ^

相信我,這一直是我最優雅的嘗試......即使它假設編譯器會從其簽名參數類型的綁定類型中推斷適當的重載+=方法是愚蠢的。幾乎所有其他的變化我嘗試在某個地方打一個類型擦除牆。

您能否提供一個方法來實現畢竟++=方法?

奇怪的是一個similarly titled question也來自圖的境界;(

叫我迷戀,但不能夠兌現這個API實在是讓人失望,所以我會很感激你的幫助和洞察力當然,我可能分裂。 ++ =僅適用於僅限頂點的方法和僅限邊緣的方法,但單獨這一點將... type刪除失敗。我也可以使用不同的名稱,這可能會導致從這個乾淨的api設計退步的方式 - 但這不包括提供一個優雅的API來我的圖書館。

+0

你'+ ='方法採取的具體子類('Vertex','Edge')抽象類'AbstractVertex'和'AbstractEdge',而模式匹配只確保您有抽象類型的實例。您是否嘗試過對特定的「頂點」和「邊緣」類型​​進行模式匹配?嗯,沒有那種類型的擦除警告。 – Shadowlands

+0

爲什麼ID需要是模板參數?如果Vertex從非模板AbstractVertex下降,您是否還會遇到同樣的問題?或者可能你應該嘗試刪除它們的共同可增加的祖先? – Ashalynd

+0

@Ashalynd這是因爲我把類型的頂點id留給了庫的調用者,因爲scala非常豐富;)在可以用作鍵的類型中,所以我會聚集在一起。 – matanster

回答

0

我似乎已經解決了它在上面我貼出的代碼,通過使用脅迫如下,但會檢查所有其他simplifica以上評論tions和可能性。

case v : AbstractVertex[ID] => += (v.asInstanceOf[Vertex]) 
case e : AbstractEdge[ID] => += (e.asInstanceOf[Edge]) 

對這種解決方案的評論當然是最受歡迎的。

+0

我喜歡在標準的scala庫中使用強制,比如併發的TrieMap。無論如何,我通過密封來控制「可加」,作爲額外的預防措施。 – matanster

2

我想我可以讓過去的類型擦除問題,我使用隱式ClassTags是指在我的評論:

// Add implicit ClassTag references to AbstractGraph types: 
abstract class AbstractGraph[ID, Vertex <: AbstractVertex[ID] : ClassTag, Edge <: AbstractEdge[ID] : ClassTag] { 

    def += (vertex: Vertex): AbstractGraph[ID, Vertex, Edge] 

    def += (edge: Edge): AbstractGraph[ID, Vertex, Edge] 

    def ++= (inputs: Addable*): AbstractGraph[ID, Vertex, Edge] = { 
    inputs.foreach(i => i match { 
     case v : Vertex => this += v 
     case e : Edge => this += e 
    }) 
    this 
    } 
} 

// ... rest as before 
+0

我猜'ClassTag'應該總是用來擦除類型擦除,呵呵?那麼最壞或最不可靠的是,我的強制還是反思? :)通過'asInstanceOf' – matanster

+2

@馬特Coersion是脆弱的(如果我管理,或設計,在不同的子類'AbstractVertex [ID]'?的通過),因此,應該被視爲一個代碼的氣味。 'ClassTag'和'TypeTag'專門用作規避Java類型刪除的手段,因此看起來像是處理這些類型情況的自然選擇。因此使用反射看起來像是過度殺傷。 – Shadowlands

+0

根據你最近的評論@Shadowlands關於過度殺傷不是'ClassTag'和'TypeTag'本身是一種反思手段?我真的很感激評論。 – matanster