Scalaで、私は構成を見てきました
trait T extends S
と
trait T { this: S =>
同様のことを実現するために使用されます(つまりS
、インスタンスを作成する前に、の抽象メソッドを定義する必要があります)。それらの違いは何ですか?なぜあなたは一方を他方の上に使うのですか?
Scalaで、私は構成を見てきました
trait T extends S
と
trait T { this: S =>
同様のことを実現するために使用されます(つまりS
、インスタンスを作成する前に、の抽象メソッドを定義する必要があります)。それらの違いは何ですか?なぜあなたは一方を他方の上に使うのですか?
自己型アノテーションを使用すると、循環依存関係を表現できます。例えば:
trait A extends B
trait B { self: A => }
これは、単純な継承では不可能です。
依存関係の管理には自己型を使用します。この特性では、別の特性を混在させる必要があります。また、継承を使用して、別の特性またはインターフェースを改良します。
例として:
trait FooService
trait FooRemoting { this : FooService => }
trait FooPersistence { this : FooService => }
object Services extends FooService with FooRemoting with FooPersistence
さて、FooRemotingとFooPersistenceの両方がFooServiceから継承され、FooServiceにメンバーとメソッドがある場合、サービスはどのようになりますか?
一方、継承については、次のようなものがあります。
trait Iterator[T] {
def hasNext : boolean
def next : T
}
trait InfiniteIterator[T] extends Iterator[T] {
def hasNext = true
}
質問をして以来、私はこれらの投稿に出くわしました:
Spiros Tzavellasは、パブリックインターフェイスとしてトレイトを使用し、実装クラスで混合する必要があるヘルパーとしてセルフタイプを使用することについて説明しています。
結論として、メソッドの実装をトレイト内に移動したい場合は、具体的なメソッドの実装をサポートし、トレイトの主な責任とは無関係の抽象的なメソッドで、これらのトレイトのインターフェイスを汚染するリスクがあります。この問題の解決策は、これらの抽象メソッドを他のトレイトに移動し、自己型アノテーションと多重継承を使用してトレイトを一緒に構成することです。
例えば:
trait PublicInterface { this: HelperTrait =>
// Uses helperMethod
}
trait HelperTrait {
def helperMethod = // ...
}
class ImplementationClass extends PublicInterface with HelperTrait
Tour of Scalaでは、抽象型メンバーでの自己型アノテーションの使用について説明しています。おそらく、抽象型メンバーには不可能extend
です(?)
私はこの質問が古いことを知っていますが、いくつかの説明と例を追加したいと思います。
特性の継承と自己タイプの間には3つの主な違いがあります。
継承は、オブジェクトパラダイムの最も結合性の高い関係の1つであり、AがBを拡張する場合、それはAがBであることを意味します。
次のコードがあるとしましょう。
trait Animal {
def stop():Unit = println("stop moving")
}
class Dog extends Animal {
def bark:String = "Woof!"
}
val goodboy:Dog = new Dog
goodboy.bark
// Woof!
犬は動物だと言っています。私たちはメッセージを送ることができます、bark
そしてstop
犬goodboy
なので、それは両方の方法を理解します。
ここで、新しい特性があるとします。
trait Security {
this: Animal =>
def lookout:Unit = { stop(); println("looking out!") }
}
今回のセキュリティは動物ではありません。セキュリティが動物であると断言すると意味的に正しくないため、これらは異なる概念であり、一緒に使用できます。
これで、新しい種類の犬を作成できます。
val guardDog = new Dog with Security
guardDog.lookout
// stop moving
// looking out!
guardDog
犬、動物、セキュリティです。それは理解しますstop
、bark
そしてそれlookout
は安全な犬だからです。
しかし、このような新しい犬を作成するとどうなりますか?
val guardDog2:Dog = new Dog with Security
guardDog2.lookout // no such method!
guardDog2
は単なる犬なので、lookout
メソッドを呼び出すことはできません。(オコク、それはセキュリティのある犬ですが、私たちはただ犬を見ています)
自己型を使用すると、型間に循環依存関係を作成できます。
trait Patient {
this: Reader =>
def isQuite:Boolean = isReading
def isSlow:Boolean = true
}
trait Reader {
this: Patient =>
def read():Unit = if(isSlow) println("Reading Slow...") else println("Reading Fast...")
def isReading = true
}
val person = new Patient with Reader
次のコードはコンパイルされません。
trait Patient extends Reader { /** code **/}
trait Reader extends Patient { /** code **/ }
この種のコードは、依存性注入(ケーキパターン)では非常に一般的です。
最後になりましたが、私たちのトレイトを使用する人は、それらが使用される順序を決定できます。したがって、トレイト線形化のおかげで、使用されるトレイトは同じですが、最終結果は異なる可能性があります。
通常の継承ではそれを行うことはできず、特性とクラスの関係は固定されています。
trait Human {
def isGoodForSports:Boolean
}
trait Programmer extends Human {
def readStackOverflow():Unit = println("Reading...")
override def isGoodForSports: Boolean = false
}
trait Sportsman extends Human {
def play():Unit = println("Playing something")
override def isGoodForSports: Boolean = true
}
val foo = new Programmer with Sportsman
foo.isGoodForSports
// true
val bar = new Sportsman with Programmer
bar.isGoodForSports
// false
これがお役に立てば幸いです。
答えは「循環性」です。しかし、それだけではありません。
自己型注釈は、継承の基本的な問題を解決します。継承元は、自分が何であるかを使用できません。セルフタイプで、すべてが簡単になります。
私のパターンは次のとおりで、縮退したケーキと見なすことができます。
trait A { self: X => def a = reuseme}
trait B { self: X => def b = a }
class X extends A with B { def reuseme=null }
クリーンに入力したまま、アセンブリ内のどこからでも呼び出すことができる複数の動作でクラスを分解できます。ケーキのパターンで頻繁に(そして間違って)識別される痛みを伴う間接参照の必要はありません。
過去10年間の複雑なJavaDIフレームワークの半分(全体ではないにしても)は、もちろんタイピングなしでこれを行うために費やされてきました。このドメインでまだJAVAを使用している人々は、明らかに時間を失っています:「SCALAouakbar」。
それはあなたの質問に答えませんが、私は自己型注釈を理解しようとしていて、基本的に答えに迷いました、そしてどういうわけかあなたの質問のバリエーションを循環することになりました。
そこで、ここでは、自己型アノテーションがよく示されているユースケースの説明を投稿します。つまり、サブタイプとしての「this」のタイプセーフなケースのようなものです。
http://programming-scala.labs.oreilly.com/ch13.html#SelfTypeAnnotationsAndAbstractTypeMembers
たまたまこの質問にたどり着いた人たちに役立つことを願っています(そして、私のように、探索を始める前にscalaの本を読む時間がありませんでした:-))