Scala:如何两次继承相同的特征? [英] Scala: How to inherit the same trait twice?

查看:128
本文介绍了Scala:如何两次继承相同的特征?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遵循的是Odersky的在Scala中编程"第二版,以及第12.5节作为可堆叠修改的特性",他介绍了IntQueue以及一个特征,该特征使您插入队列中的任何值加倍: /p>

I'm following along in Odersky's "Programming in Scala" 2nd edition, and in section 12.5 "Traits as stackable modifications", he presents an IntQueue along with a trait that doubles any values you insert into the queue:

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".考虑到这一点,我认为这与线性化的局限性有关.特别是给定的特征不能在类层次结构的线性化中出现两次.

The book then shows that you can instantiate a queue which doubles every integer you insert into it via new BasicIntQueue with Doubling. What I wanted to do was created a similar queue which multiplies every integer by 4, like this: new BasicIntQueue with Doubling with Doubling. However, this triggers a compile error "trait Doubling is inherited twice". Looking into this, I guess this has something to do with the limitations of linearlization; specifically that a given trait cannot appear twice in the linearlization of a class hierarchy.

那么,达到我想要的效果的最佳方法是什么?

What's the best way, then, to achieve the effect I want?

如果答案取决于此,这里有更多关于现实世界"用例的信息:

Here's a bit more information on my "real world" use case, in case the answer depends on this:

我有一个类SoundFile,该类读取.wav文件,并产生一个SoundFile对象,该对象扩展了WaveForm特性. SoundFile类类似于上面的BasicIntQueue,并且WaveForm特性类似于上面的IntQueue.

I have a class SoundFile, which reads a .wav file, and yields a SoundFile object, which extends a WaveForm trait. The SoundFile class is analogous to the BasicIntQueue above, and the WaveForm trait is analogous to the IntQueue above.

我有2个与Doubling类似的特质,一个称为Echo,另一个称为Reverse.

I have 2 traits that are analogous to Doubling, one called Echo and one called Reverse.

我想写new SoundFile("myFile.wav") with Reverse with Echo with Reverse,但是遇到两次关于从Reverse特征继承的相同编译错误.

I wanted to write new SoundFile("myFile.wav") with Reverse with Echo with Reverse, but I ran into that same compile error about inheriting from the Reverse trait twice.

推荐答案

不幸的是,您不能两次继承相同的特征.相反,您应该使用其他机制.例如,ReverseEcho都是波形的操纵.你可能有

Unfortunately you can't inherit from the same trait twice. Instead you should use some other mechanism. For instance, Reverse and Echo are both manipulations of the waveform. You could have

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)

或类似的东西.

如果您需要的不仅仅是简单功能的更改,则必须将对功能的修改封装在自己的类中:

If you require more changes than just a simple function, you'll have to encapsulate the modifications to functionality in your own class:

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

这篇关于Scala:如何两次继承相同的特征?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆