gpt4 book ai didi

scala - 如何继承泛型工厂方法?

转载 作者:行者123 更新时间:2023-12-04 12:37:59 26 4
gpt4 key购买 nike

假设您有一个类 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 时玩得很开心,我真的很想让它发挥作用。如果我走错了路,请告诉我。 :)

最佳答案

而不是扩展ArrayBuffer[Person]可以直接使用pimp my library pattern .这个想法是使PersonsArrayBuffer[Person]完全可以互换。

class Persons(val self: ArrayBuffer[Person]) extends Proxy {
def names = self map { _.name }

// ... other methods ...
}

object Persons {
def apply(ps: Person*): Persons = ArrayBuffer(ps: _*)

implicit def toPersons(b: ArrayBuffer[Person]): Persons = new Persons(b)

implicit def toBuffer(ps: Persons): ArrayBuffer[Person] = ps.self
}

Persons 伴随对象中的隐式转换允许您在有 Persons 引用时使用任何 ArrayBuffer 方法,反之亦然。

例如,你可以做
val l = Persons(new Person("Joe"))
(l += new Person("Bob")).names

请注意 lPersons ,但您可以调用 ArrayBuffer.+=方法,因为编译器会自动添加对 Persons.toBuffer(l) 的调用. += 的结果方法是 ArrayBuffer ,但您可以调用 Person.names因为编译器插入了对 Persons.toPersons 的调用.

编辑:

您可以使用更高种类的类型来概括此解决方案:
class Persons[CC[X] <: Seq[X]](self: CC[Person]) extends Proxy {
def names = self map (_.name)
def averageAge = {
self map (_.age) reduceLeft { _ + _ } /
(self.length toDouble)
}
// other methods
}

object Persons {
def apply(ps: Person*): Persons[ArrayBuffer] = ArrayBuffer(ps: _*)

implicit def toPersons[CC[X] <: Seq[X]](c: CC[Person]): Persons[CC] =
new Persons[CC](c)

implicit def toColl[CC[X] <: Seq[X]](ps: Persons[CC]): CC[Person] =
ps.self
}

这使您可以执行以下操作
List(new Person("Joe", 38), new Person("Bob", 52)).names

或者
val p = Persons(new Person("Jeff", 23))
p += new Person("Sam", 20)

请注意,在后一个示例中,我们调用 +=Persons .这是可能的,因为 Persons “记住”基础集合类型,并允许您调用在该类型中定义的任何方法(在这种情况下为 ArrayBuffer,由于 Persons.apply 的定义)。

关于scala - 如何继承泛型工厂方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3374923/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com