如何设计返回路径依赖类型的方法?在下面的示例中,我故意希望Vertex
依赖于Tree
路径,这样就禁止在树之间混合顶点(这只是一个例子):
trait Tree {
trait Vertex
def root: Vertex
def addChild(parent: Vertex): Vertex
}
trait TreeFactory { def make: Tree }
现在无法构建以下内容:
def test(f: TreeFactory): (Tree, Map[Tree#Vertex, Tree#Vertex]) = {
val t = f.make
var sq = IndexedSeq(t.root)
var m = Map.empty[t.Vertex, t.Vertex]
for( i <- 1 to 100) {
val p = sq(util.Random.nextInt(sq.size))
val c = t.addChild(p)
m += c -> p
sq :+= c
}
(t, m)
}
因为我返回的地图显然不应该有类型Tree#Vertex
的键和值,而是路径相关的顶点...
error: type mismatch;
found : scala.collection.immutable.Map[t.Vertex,t.Vertex]
required: Map[Tree#Vertex,Tree#Vertex]
Note: t.Vertex <: Tree#Vertex, but trait Map is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: Tree#Vertex`. (SLS 3.2.10)
(t, m)
^
如果我尝试解耦树创建和父子映射构建:
def test(t: Tree): Map[t.Vertex, t.Vertex] = {
var sq = IndexedSeq(t.root)
var m = Map.empty[t.Vertex, t.Vertex]
for (i <- 1 to 100) {
val p = sq(util.Random.nextInt(sq.size))
val c = t.addChild(p)
m += c -> p
sq :+= c
}
m
}
此失败的原因是另一个原因:"error: illegal dependent method type"
答案 0 :(得分:3)
我扭曲的想法想出了这个。我希望有一个更优雅的解决方案:
trait Gagaism {
val tree: Tree
val map: Map[tree.Vertex, tree.Vertex]
}
def test(f: TreeFactory) = new Gagaism {
val tree = f.make
val map = {
var sq = IndexedSeq(tree.root)
var m = Map.empty[tree.Vertex, tree.Vertex]
for (i <- 1 to 100) {
val p = sq(util.Random.nextInt(sq.size))
val c = tree.addChild(p)
m += c -> p
sq :+= c
}
m
}
}
答案 1 :(得分:1)
我认为您可以使用-Xexperimental -Ydependent-method-types
为依赖方法类型启用实验支持。
答案 2 :(得分:0)
我不太了解类型系统,足以解释为什么你的第一次尝试不起作用,但这是我通常遵循的模式(带有有界抽象类型的成员),它会编译。很高兴看到Tree
和TreeFactory
的实施更加自信。
package trees
trait Tree {
trait Vertex
type V <: Vertex
def root: V
def addChild(parent: V): V
}
trait TreeFactory { def make : Tree }
object Test {
def test(f: TreeFactory): (Tree, Map[Tree#Vertex, Tree#Vertex]) = {
val t = f.make
var sq = IndexedSeq(t.root)
var m = Map.empty[t.Vertex, t.Vertex]
for (i <- 1 to 100) {
val p = sq(util.Random.nextInt(sq.size))
val c = t.addChild(p)
m += c -> p
sq :+= c
}
(t, m)
}
}