特性の自己タイプA
:
trait B
trait A { this: B => }
「A
拡張も行わない具体的なクラスに混在させることはできないB
」と述べています。
一方、次のとおりです。
trait B
trait A extends B
「(具象または抽象)クラスが混在すると、A
B も混在する」と述べています。
これら 2 つのステートメントは同じことを意味しているのではないですか? self-type は、単純なコンパイル時エラーの可能性を生み出すだけであるようです。
何が足りないのでしょうか?
ベストアンサー1
主に以下の用途に使用されます依存性注入ケーキパターンのような、素晴らしい記事Scalaにおける依存性注入のさまざまな形式をカバーしており、その中にはCakeパターンも含まれています。Googleで「CakeパターンとScala」と検索すると、プレゼンテーションやビデオを含む多くのリンクが見つかります。今のところ、別の質問。
さて、自己型とトレイトの拡張の違いは何かというと、それは簡単です。 とするとB extends A
、は にB
なりますA
。自己型を使用する場合、には がB
必要ですA
。自己型によって作成される特定の要件が 2 つあります。
- が拡張される場合は
B
、をミックスインする必要がA
あります。 - 具体的なクラスが最終的にこれらの特性を拡張/ミックスインする場合、何らかのクラス/特性が を実装する必要があります
A
。
次の例を考えてみましょう。
scala> trait User { def name: String }
defined trait User
scala> trait Tweeter {
| user: User =>
| def tweet(msg: String) = println(s"$name: $msg")
| }
defined trait Tweeter
scala> trait Wrong extends Tweeter {
| def noCanDo = name
| }
<console>:9: error: illegal inheritance;
self-type Wrong does not conform to Tweeter's selftype Tweeter with User
trait Wrong extends Tweeter {
^
<console>:10: error: not found: value name
def noCanDo = name
^
Tweeter
が のサブクラスである場合User
、エラーは発生しません。上記のコードでは、 が使用されるたびにが必要でしたが、には が提供されなかったため、エラーが発生しました。上記のコードがまだスコープ内にある状態で、次のことを考慮してください。User
Tweeter
User
Wrong
scala> trait DummyUser extends User {
| override def name: String = "foo"
| }
defined trait DummyUser
scala> trait Right extends Tweeter with User {
| val canDo = name
| }
defined trait Right
scala> trait RightAgain extends Tweeter with DummyUser {
| val canDo = name
| }
defined trait RightAgain
を使用するとRight
、 をミックスインするという要件は満たされます。ただし、上記の 2 番目の要件は満たされません。を拡張するクラス/特性User
の実装の負担は依然として残ります。User
Right
両方のRightAgain
要件が満たされます。 およびUser
の実装User
が提供されます。
より実用的な使用例については、この回答の冒頭にあるリンクを参照してください。しかし、これで理解していただけたと思います。