问题描述
背景信息:我目前正试图建立一个包含几种不同搜索算法的通用图库(我已经开始使用Dijkstra的)。我已经设置了几个特征来表示可以在某些类型的图表中找到的方法(例如加权,定向): 特征GraphOps [V,E] {...}
trait WeightedGraphOps [V,E]扩展GraphOps [V,E] {...}
特性DirectedGraphOps [V,E] V,E] {...}
对象GraphOps {
def Dijkstra [V,E,G }
其他地方,我有一堂课作为我想运行Dijkstra算法的加权有向图的具体实现:
class GraphMap [T](。 ..)
使用WeightedGraphOps [Position,Edge]与DirectedGraphOps [Position,Edge] {...}
$扩展scala.collection.mutable.Map [Position,T]
c $ c>
但是当我尝试测试时:
val graph = new GraphMap [Int](...)
val(dist,prev)= GraphOps.Dijkstra(graph,Position(0,0))
问题:编译期间出现以下错误: error:推断类型参数[com.dylan.data.Position,Nothing,com.dylan.data.GraphMap [Int]]不符合方法Dijkstra的类型参数边界[V,E,G<:com.dylan.data.WeightedGraphOps [V ,E] with com.dylan.data.DirectedGraphOps [V,E]]
我花了很长时间才注意到它推断出我的边缘( E
)类型为 Nothing
,但我不明白为什么它没有成功推断它应该是 Edge
。为什么它不能推断这个类型参数,我该如何解决它?
我尝试着做下面的事情,并且让它起作用,但这对于一种应该是一种便利方法的东西来说似乎非常不方便:
类型有帮助= WeightedGraphOps [位置,边缘]与DirectedGraphOps [位置,边缘]
val(dist,prev)= GraphOps.Dijkstra [位置,边缘,有帮助](图形,位置(0,0))
Daniel可能是对的,现有的Scala类型推理器需要更直接的找出 E
必须是 Edge
的信息。此外,我的理解是,类型推断有意未被指定,以供将来改进。
无论如何,我认为您可以采取另一种方法来设计您的设计解决类型推断问题:使用类型成员而不是参数。我已经用下面的自包含代码说明了我的意思。关键的想法是类型 E
和 V
成为 GraphOps $ c的一部分$ c> type,但它们仍然可以通过使用 type refinement 来表现为类型参数,如
Dijkstra
方法。
trait GraphOps {type E;类型V}
trait WeightedGraphOps extends GraphOps {}
trait DirectedGraphOps extends GraphOps {}
object GraphOps {
def Dijkstra [V0,G with(DirectedGraphOps {type V = V0})]
(graph:G,start:V0)= {}
}
case class Position x:Int,y:Int)
case class Edge()
case class GraphMap [T]()将DirectedGraphOps扩展为WeightedGraphOps {
type E = Edge
类型V =位置
}
对象测试{
val graph = new GraphMap [Int]()
GraphOps.Dijkstra(graph,Position(0,0) )
}
编辑:
Edit2 Ignore the above paragraph. As Dylan mentioned in the comments, for this diamond inheritance situation, Scala nicely ensures the consistency of the type E
. For example, the following compiles fine:
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)
}
}
这篇关于斯卡拉未能推断出正确的类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!