Создание неявной функции, которая оборачивает map() в Scala с правильным типом: не для слабонервных

Я пытаюсь реализовать неявную функцию mapMetered это обертывания map и функции точно так же, как это с точки зрения возвращения правильного типа. Я попробовал это:

implicit class MeteredGenTraversablePimp[T, C[T] <: GenTraversable[T]](trav: C[T]) {
  def foreachMetered(m: Meter)(f: T => Unit) =
    m.foreach(trav)(f)

  def mapMetered[B, That](m: Meter)(f: (T) => B)(
    implicit bf: CanBuildFrom[C[T], B, That]
  ): That = {
    m.start()
    try {
      trav.map { x =>
        val z = f(x)
        m.item_processed()
        z
      } (bf)
    } finally { m.finish() }
  }
}

Но когда я пытаюсь это сделать, я получаю сообщение об ошибке:

[info] Compiling 1 Scala source to /Users/benwing/devel/textgrounder/target/classes...
[error] /Users/benwing/devel/textgrounder/src/main/scala/opennlp/textgrounder/util/metering.scala:223: type mismatch;
[error]  found   : scala.collection.generic.CanBuildFrom[C[T],B,That]
[error]  required: scala.collection.generic.CanBuildFrom[scala.collection.GenTraversable[T],B,That]
[error]         } (bf)
[error]            ^
[error] one error found

Есть похожие вопросы о переполнении стека, в том числе от Даниэля Собрала, который предлагает написать (trav: C[T] with GenTraversableLike[T]) но это не решает проблему.

1 ответ

Решение

Repr параметр в CanBuildFrom и в *Like Типы коллекций уже существуют, чтобы представлять наиболее точный тип коллекции. Решение вашей проблемы - завернуть GenTraversableLike[A,Repr] вместо C[T], Компилятор выведет точный тип как Reprи все будет работать без нареканий

implicit class MeteredGenTraversablePimp[A, Repr](trav: GenTraversableLike[A,Repr]) {
  def foreachMetered(m: Meter)(f: A => Unit) = {
    m.start()
    try {
      trav.foreach{ e => f( e ); m.item_processed() }
    } finally {
      m.finish()
    }
  }

  def mapMetered[B, That](m: Meter)(f: A => B)(
    implicit bf: CanBuildFrom[Repr, B, That]
  ): That = {
    m.start()
    trav.map { x: A =>
      try {
        val z: B = f(x)
        m.item_processed()
        z
      } finally { m.finish() }
    }(bf)
  }
}
Другие вопросы по тегам