如何使用我自己的通用“map"(正确的方式)丰富 Scala 集合? [英] How to enrich Scala collections with my own generic `map` (the right way)?
问题描述
我正在尝试使用我自己的 map
方法来丰富 Scala 集合,并且我已经接近但隐式转换不起作用.除此之外,还有什么我在这里想念的吗?我正在查看网络上的各种其他资源,包括这个问题被标记为重复的 SO 答案,并且许多在这里和那里都遗漏了一些东西(例如使用 C[A] <: GenTraversable[A]
,使用b()
代替b(xs)
,忘记Array
,忘记BitSet
等).
I'm trying to enrich Scala collections with my own map
method, and I'm close but the implicit conversion doesn't work. Besides that, is there anything else I'm missing here? I'm looking at various other resources on the Web, including SO answers that this question is being marked as duplicating, and many are missing something here and there (e.g. using C[A] <: GenTraversable[A]
, using b()
instead of b(xs)
, forgetting about Array
, forgetting about BitSet
, etc.).
implicit def conv[A,C](xs: C)(implicit ev: C <:< GenTraversableLike[A,C]) = new {
def mymap[B,D](f: A => B)(implicit b: CanBuildFrom[C,B,D]): D = b(xs).result // placeholder
}
scala> conv(List(1,2,3))
res39: java.lang.Object{def mymap[B,D](f: Int => B)(implicit b: scala.collection.generic.CanBuildFrom[List[Int],B,D]): D} = $$$$2c9d7a9074166de3bf8b66cf7c45a3ed$$$$anon$1@3ed0eea6
scala> conv(List(1,2,3))mymap(_+1)
res40: List[Int] = List()
scala> conv(BitSet(1,2,3))mymap(_+1)
res41: scala.collection.immutable.BitSet = BitSet()
scala> conv(BitSet(1,2,3))mymap(_.toFloat)
res42: scala.collection.immutable.Set[Float] = Set()
scala> List(1,2,3)mymap(_+1)
<console>:168: error: Cannot prove that List[Int] <:< scala.collection.IterableLike[A,List[Int]].
List(1,2,3)mymap(_+1)
^
scala> implicit def conv[A, C](xs: C)(implicit ev: C => GenTraversable[A]) = new {
| def mymap[B,D](f: A => B)(implicit b: CanBuildFrom[GenTraversable[A],B,D]): D =
| xs map f
| }
conv: [A, C](xs: C)(implicit ev: C => scala.collection.GenTraversable[A])java.lang.Object{def mymap[B,D](f: A => B)(implicit b: scala.collection.generic.CanBuildFrom[scala.collection.GenTraversable[A],B,D]): D}
scala> conv(Array(1)) mymap (_+1)
res6: scala.collection.GenTraversable[Int] = ArrayBuffer(2)
scala> Array(1) mymap (_+1)
<console>:68: error: No implicit view available from Array[Int] => scala.collection.GenTraversable[A].
Array(1) mymap (_+1)
^
推荐答案
我已经回答了这个关于类型推断的问题 就在上周.代码如下:
I've answered this very question about type inference just last week. Here's the code:
implicit def conv[A,C <: GenTraversable[A]](xs: C with GenTraversableLike[A,C]) = new {
def mymap[B,D](f: A => B)(implicit b: CanBuildFrom[C,B,D]): D = {
val builder = b(xs)
xs foreach { x => builder += f(x) }
builder.result
}
}
在这种特殊情况下,我可以使用 GenTraversable
而不是 GenTraversableLike
.我更喜欢后者,因为它提供更多.
I could have used GenTraversable
instead of GenTraversableLike
in this particular case. I prefer the later because it offers more.
问题在于声明 [A, C <: GenTraversable[A]]
不会指示 Scala 推断 A
来自 C
的类型.类型是根据它们在参数中的使用方式推断出来的,然后根据类型参数指定的边界进行检查.
The problem is that declaring [A, C <: GenTraversable[A]]
does not instruct Scala to infer the type of A
from the type of C
. Types are inferred based on how they are used in the parameters, and then checked against the boundaries specified by the type parameters.
因此,当我编写 xs: C with GenTraversable[A]
时,我让 Scala 知道它应该从 xs
推断 A
.编写 GenTraversableLike[A, C]
告诉 Scala 它应该为返回相同集合的方法选择一个 返回 C
的集合.这意味着您可以调用 filter
并返回 C
,而不是返回 GenTraversable
.
So when I write xs: C with GenTraversable[A]
, I let Scala know it should infer A
from xs
. And writing GenTraversableLike[A, C]
tells Scala it should pick a collection that returns C
for methods that return the same collection. This means you can call filter
and get C
back, instead of getting GenTraversable
back.
至于希望包含视图,我不知道您如何实现.
As for wishing to include views, that I don't know how you could accomplish.
这篇关于如何使用我自己的通用“map"(正确的方式)丰富 Scala 集合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!