泛型 – Scala无法推断出正确的类型参数
背景信息:我目前正在尝试建立一个包含一些不同搜索算法的通用图形库(我已经开始使用Dijkstra的).我已经设置了一些特征来表示在某些类型的图表中可以找到的方法(例如加权,定向):
trait GraphOps[V,E] { ... } trait WeightedGraphOps[V,E] extends GraphOps[V,E] { ... } trait DirectedGraphOps[V,E] { ... } object GraphOps{ def Dijkstra[V,E,G <: WeightedGraphOps[V,E] with DirectedGraphOps[V,E]](graph:G,start:V) = { ... } } 在其他地方,我有一个类作为加权有向图的具体实现,我想运行Dijkstra的算法: class GraphMap[T](...) extends scala.collection.mutable.Map[Position,T] with WeightedGraphOps[Position,Edge] with DirectedGraphOps[Position,Edge] { ... } 但是当我尝试测试它时: val graph = new GraphMap[Int](...) val (dist,prev) = GraphOps.Dijkstra(graph,Position(0,0)) 问题:编译期间出现以下错误:错误:推断类型参数[com.dylan.data.Position,Nothing,com.dylan.data.GraphMap [Int]]不符合方法Dijkstra的类型参数界限[V,G<:com.dylan.data.WeightedGraphOps [V,E] with com.dylan.data.DirectedGraphOps [V,E]] 附:我尝试了以下操作,并让它工作,但这似乎非常不方便本来应该是一个方便的方法: type Helpful = WeightedGraphOps[Position,Edge] val (dist,prev) = GraphOps.Dijkstra[Position,Edge,Helpful](graph,0)) 解决方法
Daniel可能是正确的,现有的Scala类型推断器需要更多的直接信息来确定E必须是Edge.此外,据我了解,类型推断是故意不明确的,以便为将来的改进让路.
无论如何,我认为您可以采用另一种解决类型推断问题的设计方法:使用类型成员而不是参数.我已经用下面的自包含代码说明了我的意思.关键思想是类型E和V成为GraphOps类型的一部分,但它们仍然可以通过使用类型细化表现为类型参数,如在Dijkstra方法中. trait GraphOps { type E; type V } trait WeightedGraphOps extends GraphOps { } trait DirectedGraphOps extends GraphOps { } object GraphOps{ def Dijkstra[V0,G <: (WeightedGraphOps{type V = V0}) with (DirectedGraphOps{type V = V0})] (graph:G,start:V0) = { } } case class Position(x: Int,y: Int) case class Edge() case class GraphMap[T]() extends WeightedGraphOps with DirectedGraphOps { type E = Edge type V = Position } object Test { val graph = new GraphMap[Int]( ) GraphOps.Dijkstra(graph,0)) } 编辑:此类型成员方法的一个潜在限制是在方法Dijkstra中对类型参数G施加较少约束.具体来说,WeightedGraphOps和DirectedGraphOps的界限不限于具有相同类型的成员E.我不知道如何解决这个问题而不会碰到你最初报告的类型推断问题.一种方法是这个问题中的模式:Why do these type arguments not conform to a type refinement?,但似乎Scala编译器无法处理它. Edit2忽略上面的段落.正如Dylan在评论中提到的,对于这个diamond inheritance情况,Scala很好地确保了类型E的一致性.例如,以下编译很好: trait GraphOps { type E; type V } trait WeightedGraphOps extends GraphOps { def f(e: E) } trait DirectedGraphOps extends GraphOps { def e: E } object GraphOps{ def Dijkstra[V0,G <: (WeightedGraphOps{type V = V0}) with (DirectedGraphOps{type V = V0})] (graph:G,start:V0) = { graph.f(graph.e) } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |