如何扩展GenSeqLike?

时间:2013-12-27 15:50:06

标签: scala

我很难理解Scalas类型系统。 编写此代码的正确方法是什么?

implicit class ExtSeq[A <: GenSeqLike[B, A], B](seq: A) {
  def prePadTo(len: Int, elem: B) = seq.reverse.padTo(len, elem).reverse
}

2 个答案:

答案 0 :(得分:4)

最简单的方法 - 只需使用Seq

implicit class ExtSeq[T](seq: Seq[T]) {
  def prePadTo(len: Int, elem: T) = seq.reverse.padTo(len, elem).reverse
}

通用方式 - 使用IsTraversableOnce

import scala.collection.GenTraversableOnce
import scala.collection.generic.{IsTraversableOnce, CanBuildFrom}

class PrePadTo[T, Repr](coll: GenTraversableOnce[T]) {
  def prePadTo[That](len: Int, elem: T)
                    (implicit cbf: CanBuildFrom[Repr, T, That]): That = {
    val b = cbf()
    val tmp = coll.toSeq
    b ++= Iterator.fill(len - tmp.size)(elem)
    b ++= tmp.iterator
    b.result
  }
}

implicit def toPrePadTo[Repr](coll: Repr)
                             (implicit traversable: IsTraversableOnce[Repr]) =
    new PrePadTo[traversable.A, Repr](traversable.conversion(coll))

用法:

scala> "abc".prePadTo(5, '-')
res0: String = --abc

答案 1 :(得分:1)

隐式类有两个问题:

  • B不受限制,因此最终会以Nothing结尾。您需要一种从输入集合中推断它的方法。

  • 您的CanBuildFrom方法需要隐式prePadTo,以便padTo方法知道如何构建输入集合的新实例。

因此:

import scala.collection.{GenSeq, GenSeqLike}
import scala.collection.generic.CanBuildFrom

implicit class ExtSeq[A <: GenSeqLike[B, A], B](seq: A with GenSeq[B]) {
  def prePadTo(len: Int, elem: B)(implicit cbf: CanBuildFrom[A, B, A]) =
    seq.reverse.padTo(len, elem).reverse
}

然后:

scala> List(1,2,3).prePadTo(10, 4)
res1: List[Int] = List(4, 4, 4, 4, 4, 4, 4, 1, 2, 3)

scala> Vector('1','2','3').prePadTo(10, '4')
res2: Vector[Char] = Vector(4, 4, 4, 4, 4, 4, 4, 1, 2, 3)

请注意,它不适用于只能隐式转换为Seq的类,例如String