如何重新参数化集合类型
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
,这也说得通。
我想定义一个泛型集合的转换。
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
,这也说得通。