如何重新参数化集合类型

how to reparameterize collection type

我想定义一个泛型集合的转换。

def transform[S<:GenIterable[T],T](s:S):S = s.zipWithIndex

这抛出:

type mismatch; found : scala.collection.GenIterable[(T, Int)] required: S

我必须在函数定义中将 S 声明为参数化 GenIterable。我想指定 "whatever the collection type was that created S, except parameterized with [(T,Int)]" 的输出类型,这样我就能保证得到相同的集合类型,而不仅仅是 GenIterable.

我怎样才能做到这一点?

这是我的存根:

def transform[S[T]<: GenIterableLike[T,S[T]],T](s:S[T])
  (implicit bf:CanBuildFrom[S[T],(T,Int),S[(T,Int)]]):S[(T,Int)] = {

  s.zipWithIndex
}

签名很糟糕,可以通过将 T 替换为 _ 来简化(或模糊)签名。

尝试一下:

scala> val m = Map("x"->"1","y"->"2")
m: scala.collection.Map[String,String] = Map(x -> 1, y -> 2)

scala> transform(m)
res3: Iterable[((String, String), Int)] = List(((x,1),0), ((y,2),1))

scala> val s = Set("x", "y")
s: scala.collection.Set[String] = Set(x, y)

scala> transform(s)
res4: scala.collection.Set[(String, Int)] = Set((x,0), (y,1))

scala> val seq = List("x", "y")
seq: List[String] = List(x, y)

scala> transform(seq)
res5: List[(String, Int)] = List((x,0), (y,1))

关键是使用 Like 特征,因为它带有正在使用的集合的类型。然后,隐式转换会处理其余部分。请注意,Map 是如何处理的。貌似隐式转换默认是将Iterable转换成List,这也说得通。