我对Traversable
有以下扩展名:
import scala.reflect.ClassTag
object ContainerHelpers {
implicit class TraversableOps[X](a: Traversable[X]) {
def partitionByType[T <: X: ClassTag]: (Traversable[T], Traversable[X]) = {
val (typed, other) = a.partition {
case _: T => true
case _ => false
}
(typed.map(_.asInstanceOf[T]), other)
}
}
// test case:
trait T
case class A(i: Int) extends T
val s = Seq[T](A(0), A(1))
val sa = s.partitionByType[A]
sa // I would like this to be Seq[A], not Traversable[A]
}
扩展程序正常,但它不保留集合类型 - 它总是返回Traversable
。我想写一下,以便partitionByType
使用partition
和map
已知的类型信息,因此sa
的类型应为(Seq[A], Seq[T])
,而不是(Traversable[A], Traversable[T])
{1}}。我怎么能这样做,也许使用更高级的类型,或类似的东西?
答案 0 :(得分:3)
您可以使用CanBuildFrom
并自行构建集合,而不是依赖TraversableLike
的实现,然后将其丢弃。这个
具有不在任何地方进行任何投射的优势,并且除了替代方案之外,它不会花费您更多,因为partition
中的TraversableLike
方法也是如此。
这是第一次获得你想要的东西(为了清晰起见我更改了参数化类型的名称):
implicit class TraversableOps[Elem, T[_Ignore] <: Traversable[_Ignore]](a: T[Elem]) {
def partitionByType[Target <: Elem: ClassTag]
(implicit cbf1: CanBuildFrom[T[Elem], Elem, T[Elem]],
cbf2: CanBuildFrom[T[Target], Target, T[Target]]) : (T[Target], T[Elem]) = {
val l = cbf2()
val r = cbf1()
for (x <- a) x match{
case t: Target => l += t
case _ => r += x
}
(l.result, r.result)
}
}
它适用于以下测试用例:
// test case:
trait A
trait B extends A
case class T(i: Int) extends A
case class U(i: Int) extends B
val s1 : List[A] = List(T(0), U(1))
val s2 : Seq[A] = List(T(0), U(1))
val sa1 = s1.partitionByType[T] //sa1 : (List[T], List[A]) = (List(T(0)),List(U(1)))
val sa2 = s2.partitionByType[T] //sa2 : (Seq[T], Seq[A]) = (List(T(0)),List(U(1)))
答案 1 :(得分:2)
使用 F-bounded容器执行此操作,例如:
//F[_] extend from Traversable for own the original type of colleciton
implicit class TraversableOps[X, F[_] <: Traversable[_]](a: F[X]) {
def partitionByType[T <: X : ClassTag]: (F[T], F[X]) = {
//cast to Traversable for known partition type
val (typed, other) = a.asInstanceOf[Traversable[X]].partition {
case _: T => true
case _ => false
}
//cast to the target type, Since the original is F-bounded, so when cast also is cast type safe
(typed.asInstanceOf[F[T]], other.asInstanceOf[F[X]])
}
}
// test case:
trait T
case class A(i: Int) extends T
case class B(i: Double) extends T
val s = Seq[T](A(0), A(1), B(2.0f))
val sa: (Seq[A], Seq[T]) = s.partitionByType[A]
println(sa._1)
println(sa._2)