我正在跟随Odersky的“Scala编程”第2版,在第12.5节“Traits as stackable modification”中,他提供了一个IntQueue
以及一个特性,可以将您插入队列的任何值加倍:
import scala.collection.mutable.ArrayBuffer
abstract class IntQueue {
def get(): Int
def put(x: Int)
}
class BasicIntQueue extends IntQueue {
private val buf = new ArrayBuffer[Int]
def get() = buf.remove(0)
def put(x: Int) { buf += x }
}
trait Doubling extends IntQueue {
abstract override def put(x: Int) {
super.put(2 * x)
}
}
然后,本书显示您可以实例化一个队列,该队列通过new BasicIntQueue with Doubling
将您插入其中的每个整数加倍。我想要做的是创建一个类似的队列,将每个整数乘以4,如下所示:new BasicIntQueue with Doubling with Doubling
。但是,这会触发编译错误“trait Doubling is inherited twice
”。考虑到这一点,我想这与线性化的局限性有关;特别是给定的特征在类层次结构的线性化中不会出现两次。
那么,实现我想要的效果的最佳途径是什么?
以下是关于我的“真实世界”用例的更多信息,如果答案取决于此:
我有一个类SoundFile
,它读取.wav文件,并生成一个SoundFile
对象,该对象扩展了WaveForm
特征。 SoundFile
类与上面的BasicIntQueue
类似,WaveForm
特征类似于上面的IntQueue
。
我有两个类似于Doubling
的特征,一个叫Echo
,一个叫Reverse
。
我想写new SoundFile("myFile.wav") with Reverse with Echo with Reverse
,但是我遇到了关于从Reverse
特征继承两次的相同编译错误。
答案 0 :(得分:3)
不幸的是,你不能两次从同一个特征继承。相反,你应该使用其他一些机制。例如,Reverse
和Echo
都是波形的操纵。你可能有
val reverse = (w: Waveform) => // produce a reverse waveform
val echo = (w: Waveform) => // copy the waveform onto itself with delay
new SoundFile("myFile.wav", reverse andThen echo andThen reverse)
或某些。
如果您需要的更改不仅仅是一个简单的函数,那么您必须将修改封装到您自己的类中:
trait Transform { self =>
def apply(w: Waveform): Waveform
def time: Double
def andThen(t: Transform) = new Transform {
def apply(w: Waveform) = t(self(w))
def time = self.time + t.time
}
}
val reverse = new Transform { def time = 0.0; def apply ... }
val echo = new Transform { def time = 1.0; def apply ... }
// Same deal after here