2016-03-23 9 views
4

私は、この例を見てみてください、言葉でこれの非常に良い説明を考え出すことはできません。積み重ねられた特性のスーパーの意味はコールサイトに依存しますか?

trait Base { def foo = "Base" } 
trait One extends Base { override def foo = "One <: " + super.foo } 
trait Two extends Base { override def foo = "Two <: " + super.foo } 

new Base with One with Two {} foo 

これは、印刷します。​​を、私は期待しています。 今、別のレベルを追加しようとしています。そのため、特質を無効にすると、明示的にsuperを呼び出す必要はありません。このように:ここで

trait Base { def foo = "Base" } 
trait Foo extends Base { def bar = foo + " <: " + super.foo } 
trait One extends Foo { override def foo = "One" } 
trait Two extends Foo { override def foo = "Two" } 

new Foo with One with Two {} bar 

、最後の行は、最後の1で、それはOneをスキップしてBaseに直接行く間、それは、Oneを意味最初の例superのように見え、Two <: Base

ので、出力します。

どうしてですか?行動は同じではありませんか?

+0

http://stackoverflow.com/questions/7694600/behaviour-of-super-in-chained-scala-traits and http://stackoverflow.com/questions/27569901/scala-traits-mixin-order-and -super-callが役立つ可能性があります。 –

+0

私は関係をもう一度見ません:最初のものは、オーバーライドされた関数呼び出しについての混乱であり、もう1つは抽象的なテンプレート対コンクリートのimlementationです。 – Dima

+0

私は後者が手掛かりになると思います。具体的ではない。 –

答えて

0

super.fooFooの定義は、Fooのスーパークラスで定義されているように、Base.fooを意味します。定義は次のとおりです。 superではなく、 "最終クラスから1つのスーパークラス"を意味する魔法のキーワードです。

ちなみに、セルフタイプを調べることもできます。 What is the difference between self-types and trait subclasses?

+1

さて、大丈夫ですが、最初の例にも同じ理由が当てはまりません: 'Base'は' Two'のスーパークラスなので、 'super.foo'は' Base.foo'を参照していないのはなぜですか? – Dima

+0

私はこれがセルフタイプとどう関係しているのか分かりません。明確にすることはできますか? – Dima

+0

hm。あなたの最初の質問、今私は確信していません... –

1

new Base with One with Two {} foo(これはnew One with Two {} fooと同じです)では、「形質スタック」はかなり明白です。 Twoにはfooがあり、fooはsuper(One)のfooと呼ばれ、fooはsuper(Base)です。

2番目のケースでは、と同じですが、new Foo with One with Two {} barの場合、「形質スタック」はBase-> Foo-> One-> Twoです。 barに電話しますが、Twoにはbarがありません。Oneにはbarがありません。 Fooにはbarがあり、そのスーパー(Base)のfooが呼び出されます。

UPDATE

@Dimaが提案したように、このMODを考えてみましょう。

trait Base { def foo = "Base" } 
trait Foo extends Base { def bar = foo + " <: " + super.foo } 
trait One extends Foo { override def bar = super.bar 
         override def foo = "One" } 
trait Two extends Foo { override def bar = super.bar 
         override def foo = "Two" } 

new One with Two {} bar // no Base or Foo needed 

はい、これは前と同じ出力が得られます。res0: String = Two <: Base

Twofoo(ないbarを呼び出してそのスーパーのbarFoo)を呼び出し、そのスーパーのbarOne)を呼び出します)のスーパーです。

すべてこれは、fooの定義とは別のアクティビティです。 Twoは、そのスーパーのfooを呼び出すことはないので、One.fooは決して使用されず、出力の一部になることはできません。

異なるアプローチが次のことを考えてみましょう。

trait B { def id = "B" } // B for Base 

trait V extends B { override def id = "V" } 
trait W extends B { override def id = "W" } 
trait X extends B { override def id = "X" } 
trait Y extends B { override def id = "Y" } 
trait Z extends B { override def id = "Z" } 

trait R extends B { override def id = "R"; def mySup = super.id } // Required 

これを複数の異なる方法でインスタンス化してみてください。いずれの場合も

val r = new V with Y with W with R with X {} // B not needed 
// or 
val r = new W with R with Z with X with V {} 
// or 
val r = new R with Y with V with B with W {} 
// or 
val r = new Z with Y with X with W with R {} 
// etc. 

r.idは、チェーン内の最後の特性となり、r.mySupは(何もR前に指定されていない場合やBRの前に来る特性になります。

+0

そのようには見えません。私は 'override def bar = super.bar'を' One'と 'Two'の両方に追加しました。あなたの" 2つはバーがなく、1つはバーがありません "というのはもはや当てはまりませんが、 。 – Dima

+0

@ jwvh:それは本当に質問に答えるものではありません。もし私が思うのであれば、ここで私はディマの困惑を理解しています: 'bar.'で' super.foo'という呼び出しが 'Base.foo'に解決されると、それは静的に/字句的に解決されているようです、動的ではない(線形化規則によって 'Two.foo'に解決される)。しかしそれが当てはまる場合、最初のケースでは 'Two.foo'の' super.foo'への呼び出しが 'Base.foo'に解決されると期待していますが、ここでは** ** * * One.fooに解決されました。 –

+0

いいえ、それは「新しい1つ2つの{バー}」と同じではありません:「新しい1つで2つ」はバーを持っていません... – Dima

関連する問題