Ben*_*ngs 41 scala traits composition self-type
在Scala中,我已经看到了这些结构
trait T extends S
Run Code Online (Sandbox Code Playgroud)
和
trait T { this: S =>
Run Code Online (Sandbox Code Playgroud)
用于实现类似的东西(即S必须在创建实例之前定义抽象方法).他们之间有什么区别?你为什么要用另一个呢?
Joa*_*ert 26
自我类型注释允许您表达循环依赖.例如:
trait A extends B
trait B { self: A => }
Run Code Online (Sandbox Code Playgroud)
简单的继承是不可能的.
Vik*_*ang 14
我将自我类型用于依赖管理:这个特性需要混合使用另一个特征.我会使用继承来改进另一个特征或接口.
举个例子:
trait FooService
trait FooRemoting { this : FooService => }
trait FooPersistence { this : FooService => }
object Services extends FooService with FooRemoting with FooPersistence
Run Code Online (Sandbox Code Playgroud)
现在,如果FooRemoting和FooPersistence都继承自FooService,而FooService有成员和方法,那么Services会是什么样子?
对于继承,我们有类似的东西:
trait Iterator[T] {
def hasNext : boolean
def next : T
}
trait InfiniteIterator[T] extends Iterator[T] {
def hasNext = true
}
Run Code Online (Sandbox Code Playgroud)
自从提出这个问题后我发现了这些帖子:
Spiros Tzavellas谈到使用特征作为公共接口和自我类型作为帮助器,必须由实现类混合.
总之,如果我们想移动内部性状的方法实现,然后我们就有可能污染与支持的具体实施办法,并与无关性状的主要责任抽象方法这些特质的接口.解决这个问题是在移动其他性状的那些抽象方法和使用自类型的注释和多重继承组成性状在一起.
例如:
trait PublicInterface { this: HelperTrait =>
// Uses helperMethod
}
trait HelperTrait {
def helperMethod = // ...
}
class ImplementationClass extends PublicInterface with HelperTrait
Run Code Online (Sandbox Code Playgroud)
斯卡拉参观讨论了使用自类型标注与抽象类型成员-想必这是不可能extend抽象类型成员(?)
我知道这个问题很老,但我想添加一些说明和示例。
trait 继承和 self 类型之间存在三个主要区别。
继承是对象范式中耦合度最高的关系之一,如果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!
Run Code Online (Sandbox Code Playgroud)
我们说狗是动物。我们可以发送消息bark,并stop给goodboy,因为是狗,它理解这两种方法。
现在假设我们有一个新特征,
trait Security {
this: Animal =>
def lookout:Unit = { stop(); println("looking out!") }
}
Run Code Online (Sandbox Code Playgroud)
这次 Security 不是 Animal,这很好,因为如果我们确认 Security 是 Animal 在语义上是不正确的,它们是不同的概念,可以一起使用。
所以现在我们可以创造一种新的狗,
val guardDog = new Dog with Security
guardDog.lookout
// stop moving
// looking out!
Run Code Online (Sandbox Code Playgroud)
guardDog是狗、动物和安全。据了解stop,bark并且lookout因为是狗与安全。
但是如果我们像这样创造一只新狗会发生什么?
val guardDog2:Dog = new Dog with Security
guardDog2.lookout // no such method!
Run Code Online (Sandbox Code Playgroud)
guardDog2只是一只狗,所以我们不能调用lookout方法。(好吧,这是一条有安全保障的狗,但我们只看到了一条狗)
Self Types 允许我们在类型之间创建循环依赖。
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
Run Code Online (Sandbox Code Playgroud)
以下代码无法编译。
trait Patient extends Reader { /** code **/}
trait Reader extends Patient { /** code **/ }
Run Code Online (Sandbox Code Playgroud)
这种代码在依赖注入(蛋糕模式)中很常见。
最后但并非最不重要的是,谁使用我们的特性可以决定它们的使用顺序,因此由于使用特性线性化,最终结果可能会有所不同,尽管使用的特性是相同的。
使用普通继承我们不能这样做,特征和类之间的关系是固定的。
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
Run Code Online (Sandbox Code Playgroud)
希望这可能有用。
| 归档时间: |
|
| 查看次数: |
7753 次 |
| 最近记录: |