我希望使用<:
而非=
覆盖特征中的抽象类型(如此处Scala Upper Bounds : value is not a member of type parameter回答)。
我想使用蛋糕模式,但这不起作用,我不明白为什么?
trait A {
def ping = println("ping")
}
trait Cake {
type T
}
trait S { this: Cake =>
type T = A
def t: T
t.ping
}
好的,这个例子运行,但在我的实际用例中,我想用<:
而不是=
覆盖类型。似乎无法访问t函数,为什么?
trait S { this: Cake =>
type T <: A
def t: T
t.ping
}
返回错误value ping is not a member of S.this.T
答案 0 :(得分:15)
这是Scala类型系统的缺点。在确定mixin中的成员时,Scala使用两个规则:首先,具体总是覆盖抽象。第二,如果两个成员都是具体的,或者都是抽象的,那么稍后以线性化顺序出现的成员将获胜。
此外,特质的自我类型
trait S { this: C => ... }
隐式增加为
trait S { this: S with C => ... }
因此可以在S中访问特征S中的定义。在您的情况下,特征S被视为:
trait S { this: S with Cake =>
type T = A
def t: T
t.ping
}
现在,只要T具体就可以了,因为它会覆盖Cake中的抽象T。但是如果T是抽象的,那么Cake中的那个在线性化顺序中出现并获胜。而且T没有上限,所以没有成员ping。解决此问题的一种方法是通过编写:
来更改线性化顺序trait S { this: Cake with S =>
type T <: A
def t: T
t.ping
}
如果Scala有一个不同的规则,即抽象类型成员的所有约束都在mixin中合并,而不是根据线性化顺序选择单个成员,那将更加清晰。这是我们将来要考虑的变化,但我们需要注意向后兼容性。