7

作为一个练习,我想将 Scala Array 集合扩展到我自己的 OneBasedArray(如您所愿,索引从 1 开始)。由于这是一个不可变的集合,我希望它在调用过滤器/映射等时返回正确的类型。

我已经阅读了这里这里这里的资源,但我很难理解如何将其转换为数组(或示例中的集合以外的集合)。我在这种结构的正确轨道上吗?

class OneBasedArray[T] 
  extends Array[T] 
  with GenericTraversableTemplate[T, OneBasedArray]
  with ArrayLike[T, OneBasedArray]

是否有任何进一步的资源可以帮助解释扩展集合?

4

5 回答 5

5

顺便说一句,我不认为 Array 是 Scala 中的集合。

于 2010-12-07T22:27:33.867 回答
3

这是一个使用始终返回其操作的可迭代对象的预期运行时类型的方法对可迭代对象进行拉皮条处理的示例:

import scala.collection.generic.CanBuildFrom

trait MapOrElse[A] {
  val underlying: Iterable[A]

  def mapOrElse[B, To]
      (m: A => Unit)
      (pf: PartialFunction[A,B])
      (implicit cbf: CanBuildFrom[Iterable[A], B, To])
      : To = {

    var builder = cbf(underlying.repr)        

    for (a <- underlying) if (pf.isDefinedAt(a)) builder += pf(a) else m(a)

    builder.result
  }
}

implicit def toMapOrElse[A](it: Iterable[A]): MapOrElse[A] =
  new MapOrElse[A] {val underlying = it}

新函数mapOrElse类似于collect函数,但它允许您传递一个方法以及一个在未定义时调用m: A => Unit的部分函数。例如可以是日志记录方法。pfpfm

于 2010-12-08T08:45:31.850 回答
3

An Arrayis not a Traversable- 尝试将其作为基类使用会导致各种问题。此外,它也不是一成不变的,这使得它完全不适合你想要的。最后,Array是一个实现——尝试从特征或抽象类继承。

于 2010-12-08T10:46:47.363 回答
2

Array 不是典型的 Scala 集合......它只是一个 Java 数组,通过隐式转换看起来像一个集合。

鉴于 Java 数组的混乱变化,你真的不想在没有非常令人信服的理由的情况下使用它们,因为它们是潜伏错误的来源。

(见这里: http: //www.infoq.com/presentations/Java-Puzzlers

像这样创建一个基于 1 的集合也不是一个好主意,因为您无法知道有多少其他集合方法依赖于序列是基于 0 的假设。所以为了安全地做到这一点(如果你真的必须),你需要添加一个新方法,保持默认方法不变:

class OneBasedLookup[T](seq:Seq) {
  def atIdx(i:Int) = seq(i-1)
}

implicit def seqHasOneBasedLookup(seq:Seq) = new OneBasedLookup(seq)

// now use `atIdx` on any sequence.

更安全的是,您可以创建一个Map[Int,T], 索引是基于一个的

(Iterator.from(1) zip seq).toMap

这可以说是最“正确”的解决方案,尽管它也会带来最高的性能成本。

于 2010-12-08T09:25:06.970 回答
0

不是数组,但这是我最近放在一起的基于一个的不可变 IndexedSeq 实现。我按照这里给出的例子,他们实现了一个 RNA 类。在该示例、ScalaDocs 和许多“有用的”编译器错误之间,我设法正确设置了它。OneBasedSeq 被泛化的事实使其比 RNA 示例复杂一点。此外,除了示例中扩展的特征和覆盖的方法之外,我还必须扩展IterableLike和覆盖该iterator方法,因为各种方法在后台调用该方法,并且默认迭代器是从零开始的。

请原谅任何风格或惯用的怪癖;我在 Scala 中编程不到 2 个月。

import collection.{IndexedSeqLike, IterableLike}
import collection.generic.CanBuildFrom
import collection.mutable.{Builder, ArrayBuffer}

// OneBasedSeq class
final class OneBasedSeq[T] private (s: Seq[T]) extends IndexedSeq[T]
  with IterableLike[T, OneBasedSeq[T]] with IndexedSeqLike[T, OneBasedSeq[T]]
{
  private val innerSeq = s.toIndexedSeq

  def apply(idx: Int): T = innerSeq(idx - 1)
  def length: Int = innerSeq.length
  override def iterator: Iterator[T] = new OneBasedSeqIterator(this)
  override def newBuilder: Builder[T, OneBasedSeq[T]] = OneBasedSeq.newBuilder
  override def toString = "OneBasedSeq" + super.toString
}

// OneBasedSeq companion object
object OneBasedSeq {
  private def fromSeq[T](s: Seq[T]) = new OneBasedSeq(s)

  def apply[T](vals: T*) = fromSeq(IndexedSeq(vals: _*))

  def newBuilder[T]: Builder[T, OneBasedSeq[T]] =
    new ArrayBuffer[T].mapResult(OneBasedSeq.fromSeq)

  implicit def canBuildFrom[T, U]: CanBuildFrom[OneBasedSeq[T], U, OneBasedSeq[U]] =
    new CanBuildFrom[OneBasedSeq[T], U, OneBasedSeq[U]] {
      def apply() = newBuilder
      def apply(from: OneBasedSeq[T]): Builder[U, OneBasedSeq[U]] = newBuilder[U]
    }
}

// Iterator class for OneBasedSeq
class OneBasedSeqIterator[T](private val obs: OneBasedSeq[T]) extends Iterator[T]
{
  private var index = 1
  def hasNext: Boolean = index <= obs.length

  def next: T = {
    val ret = obs(index)
    index += 1
    ret
  }
}
于 2013-02-13T02:55:32.903 回答