Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用成员值扩展Scala集合?_Scala - Fatal编程技术网

如何使用成员值扩展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
与mixin
timestampixin{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)