涉及使用重写方法,类型边界和...类型擦除

时间:2015-09-26 23:42:56

标签: scala

这实际上是一个涉及的场景。顶点和边线将添加到图形中。期望一种用于添加可变量的便利方法。我尝试使后一种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真是令人失望,所以我很感激你的帮助和见解。当然,我可以将++ =拆分为仅顶点方法和仅边缘方法,但仅此类型将...类型擦除失败。我也可以使用不同的名称,这可能会导致从这种干净的api设计中退回 - 但这不包括为我的库提供优雅的api。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

我似乎已经在我发布的代码上解决了它,通过使用强制如下,但将检查所有上述注释以进行其他简化和可能性。

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

关于这种解决方案的评论当然是最受欢迎的。