【发布时间】:2011-03-23 10:35:15
【问题描述】:
假设你有一个 Person 类,并通过扩展例如为它创建一个集合类。数组缓冲区:
class Persons extends ArrayBuffer[Person] {
// methods operation on the collection
}
现在,使用 ArrayBuffer,可以在伴生对象上使用 apply() 方法创建一个集合,例如:
ArrayBuffer(1, 2, 3)
您希望能够对 Persons 做同样的事情,例如:
Persons(new Person("John", 32), new Person("Bob", 43))
我的第一个直觉是扩展 ArrayBuffer 伴生对象并免费获得 apply() 方法。但似乎你不能扩展对象。 (我不太清楚为什么。)
下一个想法是使用调用 apply 的 apply() 方法创建一个 Persons 对象 ArrayBuffer的方法:
object Persons {
def apply(ps: Person*) = ArrayBuffer(ps: _*)
}
但是,这会返回一个 ArrayBuffer[Person] 而不是 Persons。
在对 ArrayBuffer 的 scaladoc 和源代码进行了一些挖掘之后,我想出了以下内容,我认为这会使 Persons 对象从 GenericCompanion 继承 apply():
编辑:
object Persons extends SeqFactory[ArrayBuffer] {
def fromArrayBuffer(ps: ArrayBuffer[Person]) = {
val persons = new Persons
persons appendAll ps
persons
}
def newBuilder[Person]: Builder[Person, Persons] = new ArrayBuffer[Person] mapResult fromArrayBuffer
}
但是,它给出了以下错误消息:
<console>:24: error: type mismatch;
found : (scala.collection.mutable.ArrayBuffer[Person]) => Persons
required: (scala.collection.mutable.ArrayBuffer[Person(in method newBuilder)])
=> Persons
def newBuilder[Person]: Builder[Person, Persons] = new ArrayBuffer[Perso
n] mapResult fromArrayBuffer
^
也许这会阻止我更进一步,但我在学习 Scala 时玩得很开心,我真的很想让它发挥作用。如果我走错了路,请告诉我。 :)
【问题讨论】:
-
你不能扩展一个对象,因为它定义了一个实例而不是一个类型。这个类比可能会有所帮助——您可以拥有 SoftwareEngineer 的子类别(例如 JavaHacker),但谈论 Martin Fowler 的子类别是没有意义的。同理,扩展实例也没有意义。
-
我认为在这里扩展是一个非常糟糕的主意。 人是一种特殊的 ArrayBuffer 吗?不,所以你显然应该更喜欢这里的构图。
-
这是一个有趣的观点,值得自己讨论,但我认为这是一个比实际更哲学的观点。 (即,为什么在实践中这是一个坏主意。)您可以说 Persons 是一系列人员,但是 Seq 是抽象的,因此您可以从具体实现 ArrayBuffer 继承。
-
在这种情况下,继承在实践中是一个坏主意,因为它将您与特定的集合实现联系在一起。假设您发现对于特定的一组人,您需要能够快速(即在恒定时间内)确定一个人是否在该组中。显然,对于这个用例,ArrayBuffer 将是一个糟糕的选择。另一方面,如果您使用组合,则 Persons 类中的方法可以同样适用,无论基础集合是 Set 还是 ArrayBuffer。
-
不,你可以使用 SeqProxy trait 免费获得这些方法:class Persons (val self: Seq[Person]) extends SeqProxy[Person]
标签: scala