4

self-type と extends の動作が異なる構成シナリオを考え出そうとしましたが、これまでのところ見つかりませんでした。基本的な例では常に、依存型のサブタイプである必要のないクラス/特性を必要としない自己型について話しますが、そのシナリオでも、自己型と拡張の間の動作は同じようです。

trait Fooable { def X: String }
trait Bar1 { self: Fooable =>
  def Y = X + "-bar"
}
trait Bar2 extends Fooable {
  def Y = X + "-bar"
}
trait Foo extends Fooable {
  def X = "foo"
}
val b1 = new Bar1 with Foo
val b2 = new Bar2 with Foo

一方を使用する場合と他方を使用する場合に、構成されたオブジェクトの構成または機能のいくつかの形式が異なるシナリオはありますか?

更新 1:セルフタイピングなしでは不可能なことの例をありがとうございます。情報に感謝しますが、self と extends が可能であるが交換可能ではないコンポジションを本当に探しています。

更新 2:私が持っている特定の質問は、なぜさまざまな Cake パターンの例で、 extends の代わりに self-type を使用する必要があると一般的に述べられているのかということだと思います。拡張でうまく機能しないケーキパターンのシナリオをまだ見つけていません

4

5 に答える 5

7

循環参照は自己型で実行できますが、extend では実行できません:

// Legal
trait A { self: B => }
trait B { self: A => }

// Illegal
trait C extends D
trait D extends C

循環依存関係がある場合、これを使用して複数のファイルに実装を分割することがあります。

于 2014-08-20T20:57:32.253 に答える
3

また、

scala> trait A { def a: String ; def s = "A" }
defined trait A

scala> trait B { _: A => def s = "B" + a }
defined trait B

scala> trait C extends A { def a = "c" ; override def s = "C" }
defined trait C

scala> new C {}.s
res0: String = C

scala> new A with B { def a = "ab" }.s
<console>:10: error: <$anon: A with B> inherits conflicting members:
  method s in trait A of type => String  and
  method s in trait B of type => String
(Note: this can be resolved by declaring an override in <$anon: A with B>.)
              new A with B { def a = "ab" }.s
                  ^

scala> new A with B { def a = "ab" ; override def s = super[B].s }.s
res2: String = Bab

ポイントがある場合、Bs は As をオーバーライドしないということです。

それは他の答えほどやる気を起こさせません。

于 2014-08-20T21:03:51.753 に答える
0

最大の違いは、最終的に公開されるインターフェイスにあります。あなたが与える例を見てみましょう(少し単純化されています):

trait Fooable { def foo: String = "foo" }
trait Bar1 { self: Fooable =>
  def Y = foo + "-bar"
}
trait Bar2 extends Fooable {
  def Y = foo + "-bar"
}
// If we let type inference do its thing we would also have foo() in the public interface of b1, but we can choose to hide it
def b1:Bar1 = new Bar1 with Fooable
// b2 will always have the type members from Bar2 and Fooable
def b2:Bar2 = new Bar2{}

// Doesn't compile - 'foo' definition is only visible inside the definition of Bar1
println(b1.foo)
// Compiles - 'foo' definition is visible outside the definition of Bar2
println(b2.foo)

そのため、クライアントに特性を混ぜていることを必ずしも知らせずに特性の機能を使用したい場合は、自己型アノテーションを使用する必要があります。

自己型注釈は、基になる型のパブリック インターフェイスを公開しません。別の型を拡張すると、常に親型のパブリック インターフェイスが公開されます。

于 2015-03-27T10:29:58.613 に答える
0

また、

self 型に関しては、混合するトレイトが必要です。クラスやオブジェクトを使用することはできません。奇妙なことに、 class を class と混在させることができるように定義できますインスタンス化しようとするとコンパイルに失敗するだけです。この質問を参照してください:

自己型クラスがクラスを宣言できる理由

于 2014-08-21T01:59:05.703 に答える