如何使用我自己的通用“map"(正确的方式)丰富 Scala 集合? [英] How to enrich Scala collections with my own generic `map` (the right way)?

查看:49
本文介绍了如何使用我自己的通用“map"(正确的方式)丰富 Scala 集合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用我自己的 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆