简体   繁体   English

Enrich-My-Library适用于所有Traversables

[英]Enrich-My-Library For all Traversables

I was trying to figure out how to write a functional swap function that works on any Traversable[_] , given a collection and the indexes to swap. 我试图弄清楚如何编写一个适用于任何Traversable[_]的函数交换函数,给定一个集合和交换索引。 I came up with the following: 我想出了以下内容:

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)

I'd like to know how to make this into an implicit extension of Traversable, enabling me to call it with List(1,2,3,4,5).swap(0, 4) . 我想知道如何将它变成Traversable的隐式扩展,使我能够用List(1,2,3,4,5).swap(0, 4)调用它。 The closest I could get was the following: 我能得到的最接近的是:

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)

Unfortunately that's not quite it. 不幸的是,这不是它。 Calling List(1,2,3,4,5).swap(0, 4) results in the following error: 调用List(1,2,3,4,5).swap(0, 4)导致以下错误:

error: No implicit view available from List[Int] => Traversable[A] 错误:List [Int]中没有隐式视图=> Traversable [A]

I feel I must be missing something, or vastly over-complicating the issue. 我觉得我必须遗漏一些东西,或者过度复杂化这个问题。 Does anyone know how this should be structured? 有谁知道这应该如何构建?


Note: This is purely academic, and not being used in a production environment in any way. 注意:这纯粹是学术性的,不以任何方式在生产环境中使用。 I'm trying to get a better handle on Scala's type system and bounds. 我正在努力更好地处理Scala的类型系统和界限。

If you're using Scala 2.10: 如果您使用的是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
  }
}

(The AnyVal thing turns it into a Value Class, meaning that the compiler will rewrite it as a static function to avoid actually doing the wrapping during runtime.) AnyVal将其转换为值类,这意味着编译器会将其重写为静态函数,以避免在运行时实际执行包装。)

If using an earlier version, drop the extends AnyVal and use an implicit-conversion function instead of implicit class : 如果使用早期版本,请删除extends AnyVal并使用隐式转换函数而不是implicit class

implicit def toTraversableWithSwap[A, Repr <: Traversable[A]](xs: TraversableLike[A, Repr]) = new TraversableWithSwap(xs)

And using it: 并使用它:

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)

Note that it doesn't actually make sense to define this function for all Traversable since some traversables (like Set , Map , etc) are unordered, so swapping two elements is meaningless. 请注意,为所有Traversable定义此函数实际上没有意义,因为某些可遍历(如SetMap等)是无序的,因此交换两个元素是没有意义的。 You probably would actually want to define it for all Seq or something. 您可能实际上想要为所有Seq或其他东西定义它。

Also: Can we also just agree to call it "enhance-my-library" already? 另外:我们也可以同意将其称为“增强我的库”吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM