如何使用成员值扩展Scala集合?
假设我有以下数据结构:如何使用成员值扩展Scala集合?,scala,Scala,假设我有以下数据结构: case class Timestamped[CC[M] < Seq[M]](elems : CC, timestamp : String) 语法很难理解,相反,我希望能够执行以下操作: Timestamped(1,2,3,4)("2014-02-25") t.head // 1 t.timestamp // "2014-05-25" 其中时间戳只是Seq的扩展,它的实现SeqLike,具有单个属性val timestamp:String 这似乎很容易
case class Timestamped[CC[M] < Seq[M]](elems : CC, timestamp : String)
语法很难理解,相反,我希望能够执行以下操作:
Timestamped(1,2,3,4)("2014-02-25")
t.head // 1
t.timestamp // "2014-05-25"
其中时间戳只是Seq
的扩展,它的实现SeqLike
,具有单个属性val timestamp:String
这似乎很容易做到;只需将Seq
与mixintimestampixin{val timestamp:String}
一起使用即可。但是我不知道如何创建构造函数我的问题是:如何在伴生对象中创建一个构造函数,以创建一个具有额外成员值的序列?签名如下:
object Timestamped {
def apply(elems: M*)(timestamp : String) : Seq[M] with TimestampMixin = ???
}
你会发现这并不简单;集合使用
Builder
s来实例化自身,因此我不能简单地将构造函数称为覆盖某些val
s。Scala集合在本质上是非常复杂的结构。扩展Seq
需要实现apply
、length
和iterator
方法。最后,您可能会复制列表
、集
或其他内容的现有代码。您可能还需要为您的收藏担心CanBuildFrom
s,如果您只想添加一个字段,那么最终我认为这是不值得的
取而代之的是,考虑从您的代码>时间戳记< /代码>类型的隐式转换为<代码> SEQ
case class Timestamped[A](elems: Seq[A])(timestamp: String)
object Timestamped {
implicit def toSeq[A](ts: Timestamped[A]): Seq[A] = ts.elems
}
现在,每当我尝试从Seq
调用一个方法时,编译器都会隐式地将时间戳
转换为Seq
,我们可以正常进行
scala> val ts = Timestamped(List(1,2,3,4))("1/2/34")
ts: Timestamped[Int] = Timestamped(List(1, 2, 3, 4))
scala> ts.filter(_ > 2)
res18: Seq[Int] = List(3, 4)
这里有一个主要的缺点,那就是在对原始的
时间戳执行操作后,我们现在只能使用Seq
,
,,。。。extend Seq,它只有3个抽象成员:
case class Stamped[T](elems: Seq[T], stamp: Long) extends Seq[T] {
override def apply(i: Int) = elems.apply(i)
override def iterator = elems.iterator
override def length = elems.length
}
val x = Stamped(List(10,20,30), 15L)
println(x.head) // 10
println(x.timeStamp) // 15
println(x.map { _ * 10}) // List(100, 200, 300)
println(x.filter { _ > 20}) // List(30)
请记住,这只在Seq对您的用例足够具体的情况下才有效,如果您以后发现需要更复杂的集合行为,这可能会变得站不住脚
编辑:添加了一个更接近您试图创建的签名的版本。不确定这是否对您有所帮助:
case class Stamped[T](elems: T*)(stamp: Long) extends Seq[T] {
def timeStamp = stamp
override def apply(i: Int) = elems.apply(i)
override def iterator = elems.iterator
override def length = elems.length
}
val x = Stamped(10,20,30)(15L)
println(x.head) // 10
println(x.timeStamp) // 15
println(x.map { _ * 10}) // List(100, 200, 300)
println(x.filter { _ > 20}) // List(30)
如果元素最终是一个一般创建的
WrappedArray
考虑一下这个方案B。我认为如果需要从头开始构建它们,Seq扩展可能会很复杂,但是扩展Seq并通过3个抽象成员传递给现有实现可以很好地工作。非抽象成员仅在其默认实现中使用这3个方法,我希望是。True,但返回集合的方法仍将返回Seq
,这里就是这种情况。我的观点是,如果他想要一个映射
返回时间戳[a]
,那么这将非常困难。是的,正如@m-z所说,我希望它看起来像一个新的集合类型。我尝试的第一件事是实现Builder
和CanBuildFrom
;但是,尝试扩展Builder
的现有实现似乎不起作用,因为它们是合格的final
,因此我无法覆盖构造函数以接受我的新时间戳成员。谢谢@Rich Henry。实现似乎更简单。但正如您所说,这将迫使实现使用Seq
。我真正想要的是类似于GenTraversableFactory
trait的东西——参见scaladoc。所有具体的集合伴随对象都扩展了这一点,以获得几乎免费的工厂实现。在上面的问题之后,我感谢我没有在问题中明确说明这一点(这就是为什么第一个代码段在代码中有CC,CC
必须是Seq
,就像我的一样,假设
case class Stamped[T](elems: T*)(stamp: Long) extends Seq[T] {
def timeStamp = stamp
override def apply(i: Int) = elems.apply(i)
override def iterator = elems.iterator
override def length = elems.length
}
val x = Stamped(10,20,30)(15L)
println(x.head) // 10
println(x.timeStamp) // 15
println(x.map { _ * 10}) // List(100, 200, 300)
println(x.filter { _ > 20}) // List(30)