如何使用我自己的通用地图丰富 TraversableOnce? [英] How to enrich a TraversableOnce with my own generic map?

查看:45
本文介绍了如何使用我自己的通用地图丰富 TraversableOnce?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试丰富所有 TraversableOnce[String] 对象,但我无法找出构建迭代器的正确语法.这是我目前所拥有的:

I am trying to enrich all TraversableOnce[String] objects, and I can't figure out the right syntax for building iterators. This is what I have so far:

class Exclaimer[R <: TraversableOnce[String]](val lines:R) {
  import scala.collection.generic.CanBuildFrom
  def exclaim(implicit bf:CanBuildFrom[R,String,R]):R = {
    val b = bf(lines)
    lines.foreach(b += _)
    b.result
  }
}
implicit def WrapExclaimer[R <: TraversableOnce[String]](lines:R) = new Exclaimer(lines)

它适用于集合(即它返回一个与我给它的类相同的集合),但它不适用于迭代器,因为它不能构造一个 Iterator[java.lang 类型的集合.String] 具有基于 Iterator[java.lang.String] 类型的集合的 String 类型元素.我该如何解决?我使用的是 Scala 2.9(我错误地写了 2.8).

It works fine for collections (i.e. it returns an collection of the same class as I gave it), but it doesn't work for iterators, because it Cannot construct a collection of type Iterator[java.lang.String] with elements of type String based on a collection of type Iterator[java.lang.String]. How do I fix this? I'm using Scala 2.9 (edit: I mistakenly wrote 2.8).

这是一些示例输出:

scala> List("a","b","c").exclaim
res5: List[java.lang.String] = List(a, b, c)

scala> Vector("a","b","c").exclaim
res6: scala.collection.immutable.Vector[java.lang.String] = Vector(a, b, c)

scala> List("a","b","c").iterator.exclaim
<console>:10: error: Cannot construct a collection of type Iterator[java.lang.String] with elements of type String based on a collection of type Iterator[java.lang.String].
              List("a","b","c").iterator.exclaim
                                         ^

推荐答案

2.10通用解决方案

你应该使用 exclaim[That](implicit bf:CanBuildFrom[R, String, That]) 而不是 CanBuildFrom[R,String,R].另请注意,有更通用的方法来扩展类集合 - IsTraversableOnce(以及 IsTraversableLike)

General solution for 2.10

You should use exclaim[That](implicit bf:CanBuildFrom[R, String, That]) instead of CanBuildFrom[R,String,R]. Note also that there is more general way to extend collection-like classes - IsTraversableOnce (and also IsTraversableLike)

import collection.generic.IsTraversableOnce
import collection.GenTraversableOnce

class Exclaimer[A, Repr](val lines: GenTraversableOnce[A]) {
  import scala.collection.generic.CanBuildFrom
  def exclaim[That](implicit bf:CanBuildFrom[Repr, String, That], e: A =:= String): That = {
    val b = bf()
    lines.foreach(s => b += e(s))
    b.result
  }
}
implicit def wrapExclaimer[Repr](r: Repr)(implicit fr: IsTraversableOnce[Repr]): Exclaimer[fr.A,Repr] =
  new Exclaimer[fr.A, Repr](fr.conversion(r))

此方法适用于Array:

Array("a","b","c").exclaim
// Array[String] = Array(a, b, c)

修复了初始实现

这是您的初始实现(已修复).它适用于 Iterator,但在 Array 上失败,因为 Array 不是 TraversableOnce:

Fixed initial implementation

Here is your initial implementation (fixed). It works with Iterator, but fails on Array since Array is not TraversableOnce:

class Exclaimer[R <: TraversableOnce[String]](val lines:R) {
  import scala.collection.generic.CanBuildFrom
  def exclaim[That](implicit bf:CanBuildFrom[R,String,That]):That = {
    val b = bf(lines)
    lines.foreach(b += _)
    b.result
  }
}
implicit def WrapExclaimer[R <: TraversableOnce[String]](lines:R) = new Exclaimer(lines)

scala> List("a","b","c").iterator.exclaim
res0: Iterator[String] = non-empty iterator

scala> Array("a","b","c").exclaim
<console>:10: error: value exclaim is not a member of Array[String]
              Array("a","b","c").exclaim
                                 ^

CanBuildFrom

scala 2.9.3 中没有 IsTraversableOnce,因此您必须使用初始方法的固定版本.但是你会得到 TraversableOnce 而不是 Iterator.

CanBuildFrom

There is no IsTraversableOnce in scala 2.9.3, so you have to use fixed version of your initial approach. But you'll get TraversableOnce instead of Iterator.

List("a","b","c").iterator.exclaim
// scala.collection.TraversableOnce[String] = non-empty iterator

要获得 Iterator,您必须像这样创建自己的隐式 CanBuildFrom:

To get Iterator you have to create your own implicit CanBuildFrom like this:

import collection.generic.CanBuildFrom
import collection.mutable.Builder
import collection.immutable.VectorBuilder

implicit def iteratorCbf[A, B] = new CanBuildFrom[Iterator[A], B, Iterator[B]]{
  def apply(): Builder[B, Iterator[B]] = new Builder[B, Iterator[B]]{
    private[this] val inner = new VectorBuilder[B]
    def +=(elem: B) = {
      inner += elem
      this
    }
    def clear(): Unit = inner.clear()
    def result(): Iterator[B] = inner.result().iterator
  }
  def apply(i: Iterator[A]) = apply()
}

不,你会得到 Iterator[String] 而不是 TraversableOnce[String]:

No you'll get Iterator[String] instead of TraversableOnce[String]:

List("a","b","c").iterator.exclaim
// Iterator[String] = non-empty iterator

您应该将隐式 iteratorCbf 方法添加到您的 Exclaimer 类的伴随对象中.

You should add implicit iteratorCbf method into companion object of your Exclaimer class.

这篇关于如何使用我自己的通用地图丰富 TraversableOnce?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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