2012-04-18 53 views
8

我想用<:而不是=(如在此处的答案Scala Upper Bounds : value is not a member of type parameter)覆盖特征中的抽象类型。重写抽象类型的蛋糕模式不适用于Upper Type Bounds

我想用蛋糕模式,但这不起作用,我不明白为什么?

trait A { 
    def ping = println("ping") 
} 

trait Cake { 
    type T 
} 

trait S { this: Cake => 
    type T = A 
    def t: T 
    t.ping 
} 

OK,这个例子来看,但在我的实际使用情况下,我想<:,而不是覆盖型与=。它似乎是不可能的访问T功能,为什么呢?

trait S { this: Cake => 
    type T <: A 
    def t: T 
    t.ping 
} 

返回一个错误value ping is not a member of S.this.T

回答

15

这是Scala的类型系统的缺点。在确定mixin中的成员时,Scala使用两条规则:首先,具体总是覆盖抽象。第二,如果两个成员都是具体的,或者两者都是抽象的,那么后来以线性化顺序出现的那个成功。

此外,

trait S { this: C => ... } 

被隐式地扩充以

trait S { this: S with C => ... } 

使得在性状界说可以内S.访问在你的情况中,性状S上性状的自类型被视为:

trait S { this: S with Cake => 
    type T = A 
    def t: T 
    t.ping 
} 

现在,只要T是具体的,这很好,因为它覆盖了ab在T蛋糕中做T。但是如果T是抽象的,Cake中的那个稍后以线性化顺序出现并获胜。而且这个T没有上限,所以没有成员ping。解决这个问题的方法之一是通过写作来改变线性顺序:

trait S { this: Cake with S => 
    type T <: A 
    def t: T 
    t.ping 
} 

这将是清洁的,如果斯卡拉有不同的规则,即抽象类型成员的所有约束中混入被合并,而不是挑选根据线性化顺序的单个成员。这是我们未来想要考虑的变化,但我们需要注意向后兼容性。