带有泛型的隐式 scala class

Implicit scala class with generics

我有这个代码:

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
    }
}

while 让我写类似 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 <: TraversableT[A] <: Traversable[A],但无法以隐式转换起作用的方式进行编译。

我觉得这应该是可行的,但我对 Scala 不够熟悉,无法正确理解语法。

第二个通用参数是正确的做法:

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
  }
}

应该。

我看不出和上面有什么区别,这是另一个使用 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("--")