Migrating a generic append function to Scala 2.13 collections

时间:2019-03-17 22:32:24

标签: scala

I have the following extension class that adds a myAppend method to anything SeqLike.

implicit class WithAppend[A, R](s: SeqLike[A, R]) extends AnyVal {
  def myAppend(i: A)(implicit cbf: CanBuildFrom[R, A, R]): R = s :+ i
}

How can I port this code to Scala 2.13 and retain similar performance characteristics? Bonus points if the extended class can remain an AnyVal

Few things I have tried:

class Extends1[R, S <: IsSeq[R]](c: R, isSeq: S) {
  def myAppend(a: isSeq.A): R = (isSeq(c) :+ a).asInstanceOf[R]
}

But the asInstanceOf is disappointing - is it even safe?

I could do:

class Extends3[S[_], A](c: SeqOps[A, S, S[A]]) {
  def myAppend(a: A): S[A] = c :+ a
}

but now we're constrained to collections of the form S[A] while the Scala 2.12 code can take any R.

1 个答案:

答案 0 :(得分:1)

我可以想出一种无需强制转换即可工作的方法签名和实现:

implicit class WithAppend[Repr](private val repr: Repr) extends AnyVal { 
  def myAppend[A0, C](a: A0)(
    implicit 
    isSeq: IsSeq[Repr]{ type A = A0 }, 
    b: BuildFrom[Repr, A0, C]
  ): C = b.fromSpecific(repr)(isSeq(repr) :+ a) 
}

很难保证它的性能,但是我怀疑它会比您以前拥有的要差得多。另一种选择是b.newBuilder(repr).addAll(isSeq(repr)).addOne(a).result()

scala> List(1,2).myAppend(3)
res3: List[Int] = List(1, 2, 3)

scala> Vector(1,2).myAppend(3)
res4: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3)

scala> "Strin".myAppend('g')
res5: String = String