我很难理解Scalas类型系统。 编写此代码的正确方法是什么?
implicit class ExtSeq[A <: GenSeqLike[B, A], B](seq: A) {
def prePadTo(len: Int, elem: B) = seq.reverse.padTo(len, elem).reverse
}
答案 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
。