scala - 为所有 Traversable 丰富我的图书馆

标签 scala types implicit enrich-my-library

我试图弄清楚如何编写一个适用于任何 Traversable[_] 的函数式交换函数,给定一个集合和要交换的索引。我想出了以下内容:

def swap[A, CC <% Traversable[A]](xs: CC, i: Int, j: Int): Traversable[A] = {
  xs.slice(0, i) ++ 
    xs.slice(j, j+1) ++ 
    xs.slice(i+1, j) ++ 
    xs.slice(i, i+1) ++ 
    xs.slice(j+1, xs.size)
}

swap(List(1,2,3,4,5), 0, 4) // => List(5,2,3,4,1)

我想知道如何使它成为 Traversable 的隐式扩展,使我能够使用 List(1,2,3,4,5).swap(0, 4) 调用它.我能得到的最接近的是以下内容:
import language.implicitConversions
class RichTraversable[A, B <% Traversable[A]](xs: B) {
  def swap(i: Int, j: Int): Traversable[A] = {
    xs.slice(0, i) ++ 
      xs.slice(j, j+1) ++ 
      xs.slice(i+1, j) ++ 
      xs.slice(i, i+1) ++ 
      xs.slice(j+1, xs.size)
  }
} 
implicit def richTraversable[A, B <% Traversable[A]](ys: B)(implicit b: Traversable[A])
  = new RichTraversable[A, B](ys)

不幸的是,事实并非如此。调用 List(1,2,3,4,5).swap(0, 4)导致以下错误:

error: No implicit view available from List[Int] => Traversable[A]



我觉得我一定遗漏了一些东西,或者让问题过于复杂。有谁知道这应该如何结构?

注意:这纯粹是学术性的,不会以任何方式用于生产环境。我试图更好地处理 Scala 的类型系统和边界。

最佳答案

如果您使用的是 Scala 2.10:

import scala.collection.generic.CanBuildFrom
import scala.collection.TraversableLike

implicit class TraversableWithSwap[A, Repr <: Traversable[A]](val xs: TraversableLike[A, Repr]) extends AnyVal {
  def swap[That](i: Int, j: Int)(implicit bf: CanBuildFrom[Repr, A, That]): That = {
    val builder = bf(xs.asInstanceOf[Repr])
    builder.sizeHint(xs)
    builder ++= xs.take(i)
    builder ++= xs.slice(j, j + 1)
    builder ++= xs.slice(i + 1, j)
    builder ++= xs.slice(i, i + 1)
    builder ++= xs.drop(j + 1)
    builder.result
  }
}

(AnyVal 东西把它变成了一个值类,这意味着编译器会将它重写为一个静态函数,以避免在运行时实际进行包装。)

如果使用早期版本,请删除 extends AnyVal并使用隐式转换函数代替 implicit class :
implicit def toTraversableWithSwap[A, Repr <: Traversable[A]](xs: TraversableLike[A, Repr]) = new TraversableWithSwap(xs)

并使用它:
scala> Vector(1,2,3,4,5,6,7,8,9).swap(2,5)
res0: scala.collection.immutable.Vector[Int] = Vector(1, 2, 6, 4, 5, 3, 7, 8, 9)

请注意,为所有 Traversable 定义此函数实际上没有意义。由于一些可遍历对象(如 SetMap 等)是无序的,因此交换两个元素是没有意义的。您可能实际上希望为所有 Seq 定义它或者其他的东西。

另外:我们也可以同意将其称为“增强我的图书馆”吗?

关于scala - 为所有 Traversable 丰富我的图书馆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15709233/

相关文章:

multithreading - 跨线程存储任意函数调用

node.js - 类静态端 'typeof _Readable' 错误地扩展了基类静态端 'typeof Readable'

scala - SBT 准备 WAR 文件,重复条目 : META-INF/MANIFEST. MF

scala - 在 sbt 运行任务中重定向标准输入/标准输出

Scala 部分应用不清楚

scala - zipper vs.迭代器,用于遍历列表或树

c - Puzzle by C 类型从 short 到 int 的提升

scala - 如何对我的解释器中使用的类型进行隐式转换

c++ - 参数或返回类型隐式转换在 C++ 中优先吗?

scala - 获取隐含证据选择的运行时类型