2013-03-29 35 views
6

我試圖弄清楚如何編寫一個功能交換函數,該函數可以在任何Traversable[_]上工作,給定一個集合和交換索引。我想出了以下情況:Enrich-My-Library對於所有遍歷器

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的類型系統和邊界。

回答

4

如果你使用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因爲一些traversables(如SetMap等)是無序的,所以交換兩個元素是沒有意義的。你可能真的想要爲所有的Seq定義它。

另外:我們是否也可以同意將其稱爲「enhance-my-library」?

+0

第一:哇,這是我從未見過的建造者?第二:是的,我們可以同意從現在開始= = – KChaloux

+0

建造者是內部集合中使用的東西。例如,請參閱:https://github.com/scala/scala/blob/master/src/library/scala/collection/TraversableLike.scala#L237 – dhg

+0

嗯。我找不到它可以找到CanBuildFrom或TraversableLike。有沒有我缺少的進口? – KChaloux