我对 Scala 比较陌生,我觉得我已经跳入了 Scala 的深处。我需要编写一组(错误,扩展)集合(一个类似于 ArrayBuffer,一个类似于 Array),它们适用于通用(但有界)类型。我对如何解决这个问题有一个想法,但我的整个方法也完全有可能是错误的。
我正在尝试做的事情的本质应该从下面的代码中清楚。我希望能够制作一个“复合对象”的集合,每个组件对象都以某种类型为界。在下面的代码中,Meal
对象可以是Meal[Beef, Broccoli]
但不能是Meal[Carrots, Broccoli]
。然后,我想为复合对象创建两个集合类(Buffer-like 和 IndexedSeq-like)。作为参考,我一直在使用The Architecture of Scala Collections。
package food
import collection.mutable.ArrayBuffer
import collection.{mutable, IndexedSeqLike}
import collection.generic.CanBuildFrom
// basic objects
abstract class Food {
val isCooked: Boolean
}
abstract class Protein extends Food
abstract class Vegetable extends Food
case class Beef(isCooked: Boolean) extends Protein
case class Fish(isCooked: Boolean) extends Protein
case class Carrots(isCooked: Boolean) extends Vegetable
case class Broccoli(isCooked: Boolean) extends Vegetable
// Composite Object
class Meal[Protein, Vegetable](protein: Protein, vegetable: Vegetable)
// Buffer Container
class MealsBuffer[Protein, Vegetable] extends ArrayBuffer[Meal[Protein, Vegetable]]
// Fixed-Size Container
final class MealsSeq[Protein, Vegetable] private (data: Array[Meal[Protein, Vegetable]])
extends IndexedSeq[Meal[Protein, Vegetable]]
with IndexedSeqLike[Meal[Protein, Vegetable], MealsSeq[Protein, Vegetable]] {
import MealsSeq._
// Mandatory re-implementation of `newBuilder` in `IndexedSeq`
override protected[this] def newBuilder: mutable.Builder[Meal[Protein, Vegetable], MealsSeq[Protein, Vegetable]] = MealsSeq.newBuilder
// Mandatory implementation of `apply` in `IndexedSeq`
def apply(idx: Int): Meal[Protein, Vegetable] = {
if (idx < 0 || length <= idx)
throw new IndexOutOfBoundsException
data(idx)
}
def length: Int = data.size
}
// Fixed-Size Container Companion Object
object MealsSeq {
def fromBuffer(buf: MealsBuffer[Protein, Vegetable]): MealsSeq[Protein, Vegetable] = fromIndexedSeq(buf.toArray)
def fromBuffer(buf: ArrayBuffer[Meal[Protein, Vegetable]]): MealsSeq[Protein, Vegetable] = fromIndexedSeq(buf.toArray)
def fromIndexedSeq(buf: Array[Meal[Protein, Vegetable]]): MealsSeq[Protein, Vegetable] = new MealsSeq[Protein, Vegetable](buf)
def fromSeq(buf: Seq[Meal[Protein, Vegetable]]): MealsSeq[Protein, Vegetable] = new MealsSeq[Protein, Vegetable](buf.toArray)
def apply(bases: Meal[Protein, Vegetable]*) = fromSeq(bases)
def newBuilder: mutable.Builder[Meal[Protein, Vegetable], MealsSeq[Protein, Vegetable]] = new ArrayBuffer mapResult fromSeq
implicit def canBuildFrom: CanBuildFrom[MealsSeq[Protein, Vegetable], Meal[Protein, Vegetable], MealsSeq[Protein, Vegetable]] =
new CanBuildFrom[MealsSeq[Protein, Vegetable], Meal[Protein, Vegetable], MealsSeq[Protein, Vegetable]] {
def apply(): mutable.Builder[Meal[Protein, Vegetable], MealsSeq[Protein, Vegetable]] = newBuilder
def apply(from: MealsSeq[Protein, Vegetable]): mutable.Builder[Meal[Protein, Vegetable], MealsSeq[Protein, Vegetable]] = newBuilder
}
}
这段代码无法编译,正如我所指出的,我在伴生对象中尤其遇到了麻烦,特别是在单例对象中实现泛型方面。
正如我所说,我对我所提出的最终不是我最终想要完成的目标的正确解决方案持开放态度。我应该以某种方式使用特征而不是抽象类吗?隐式转换而不是有界泛型和多态?有没有办法强制执行我正在尝试使用组合而不是继承组合Meals
对象?这在某种程度上是使用更高种类的类型的地方吗?Scala 有很多 Java 没有的东西,我有点头晕。
更新
澄清一下,我需要做的范围如下:我需要两个集合,一个类 Array 和一个类 ArrayBuffer。集合包含一个由一对子实体组成的实体,每个子实体都有特定的限制。在此处的示例中,集合是针对仅由一种蛋白质和一种蔬菜组成的膳食。这些集合最终将需要使用专门的行为和方法进行扩展,还需要能够覆盖方法的特定实现,以使它们对特定用例更有效。这就是任务的范围。我只是在寻找最简单的方法来完成它。