Неявный класс scala с генериками - PullRequest
0 голосов
/ 14 октября 2019

У меня есть этот код:

object Peek {
    implicit def traversableToPeek[A](underlying: Traversable[A]) = new Peek(underlying)
}
class Peek[A](underlying: Traversable[A]) {

    /**
     * Java-style peek method
     */
    def peek(func: A => Unit): Traversable[A] = {
        underlying.foreach(func)
        underlying
    }
}

, в то время как позволяет мне писать такие вещи, как List(1,2,3).peek(println).map(_+1).peek(println), который печатает 1,2,3, а затем 2,3,4 (после import Peek._)

Однако значение времени компиляции этого выражения равно Traversable[Int]. Это означает, что хотя этот код компилируется:

val l = List(1,2,3)
val l2 = 4 :: l

, этот код не:

val l = List(1,2,3).peek(println)
val l2 = 4 :: l

, поскольку :: не определено в Traversable. Цель peek состоит в том, чтобы разрешить операции только с побочными эффектами, не требуя несколько уродливых конструкций, таких как l.map(e => println(e); e)

Я попытался добавить второй универсальный параметр T <: Traversable или T[A] <: Traversable[A], но не смог его скомпилировать таким образомгде неявное преобразование работало.

Мне кажется, это возможно, но я недостаточно знаком со Scala, чтобы получить правильный синтаксис.

Ответы [ 2 ]

2 голосов
/ 14 октября 2019

Второй универсальный параметр - правильный подход:

implicit class Peek[C[X] <: Traversable[X], A](underlying: C[A]) {
  def peek(func: A => Unit): C[A] = {
    underlying.foreach(func)
    underlying
  }
}

(в Scala 2.13 замените устаревший Traversable на Iterable).

Если у вас есть расширение типаTraversable[Something], который сам по себе не является общим, вышеописанное не будет работать, но

implicit class Peek[C <: Traversable[A], A](underlying: C with Traversable[A]) {
  def peek(func: A => Unit): C = {
    underlying.foreach(func)
    underlying
  }
}

должно.

0 голосов
/ 17 октября 2019

Я не вижу большой разницы, чем выше, вот другая альтернатива, использующая CanBuildFrom

import scala.collection.generic._
import scala.language.higherKinds
implicit class CollWrapper[Coll[X] <: Traversable[X], A](coll:Coll[A]) {
    def peek(f:A => Unit)(implicit cbf:CanBuildFrom[Coll[A], A, Coll[A]]):Coll[A] = {
       val builder = cbf(coll)
       coll.foreach{elem =>
          builder += elem;
          f(elem)
       }
       coll
    }
}

List(1,2,3,4).peek(println).map(x => x * 3)
println("--")
List("One", "Two", "Three").peek(println).map(x => x + "!")
println("--")
List('c', 'd', 'e').peek(println).map(x => x + 3)
println("--")
Set("Nine", "Ten", "Twelve").peek(println).map(x => x + "!")
println("--")
Map(1 -> "One", 2 -> "Two", 3 -> "Three").peek(println).map{case (k,v) => (k, v + "!")}.toMap
println("--")
...