2013-02-18 68 views
8

我有經常發生在我的代碼如下用例:如何使用隱式轉換列表轉換[A]成列表[B]

  • 集錦[A]
  • 的隱轉換A到B

,我想獲得B的集合,我可以暗中使用如下:

case class Items(underlying:List[B]) 
    import B._ 
    def apply(a:List[A]):Items = { 
    val listOfB= a.map {implicitly[A=>B]} 
    Items(listOfB) 
    } 

在Scala中做什麼最優雅的方式,也許在Scalaz的幫助下做到這一點?

編輯:我的問題的目標是找到一個地道的方式,庫/開發者的常用方法。從這種意義上說,開發我自己的pimp-my-library解決方案是我不喜歡的,因爲編寫我的代碼的其他人不知道這個轉換的存在並且不會使用它,並且他們會重寫它們自己的。我喜歡用這種常用函數的庫方法,這就是爲什麼我想知道Scalaz中是否存在這樣一個特性。

回答

14

如果你知道類型,這很簡單。一是隱式轉換從AB

implicit def conversion(a: A): B = //... 

,那麼你需要的隱式轉換從List[S]List[T]其中ST是其隱式轉換從ST存在任意類型:

implicit def convList[S, T](input: List[S])(implicit c: S => T): List[T] = 
    input map c 

這應該然後工作:

val listOfA: List[A] = //... 
val listOfB: List[B] = listOfA 

這是由編譯器解析爲:

val listOfB: List[B] = convList(listOfA)(conversion) 

其中SATB

+0

它是某種標準庫的一部分嗎?我討厭重新發明輪子 – Edmondo1984 2013-02-18 17:41:12

+0

@ Edmondo1984:不知道,我從頭開始寫了它,但我也可能重新發明輪子。順便再讀一遍我的答案,我爲此解決方案進行了整合,因此對於任何可轉換類型,只需一個'convList'隱式轉換。 – 2013-02-18 17:52:00

9

我不會用這裏的隱式轉換,但在課堂上結合一個觀點:

case class Foo(x: Int) 
case class Bar(y: Int) 
implicit def foo2Bar(foo: Foo) = Bar(foo.x) 
case class Items[A <% Bar](xs: List[A]) { 
    def apply(x: Int): Bar = xs(x) 
} 

現在,您可以用Foo列表中創建的Items一個實例,並在內部使用它們,如果他們分別是Bar s。

scala> Items(List(Foo(1))) 
res8: Items[Foo] = Items(List(Foo(1))) 

scala> res8(0) 
res9: Bar = Bar(1) 

編輯

一些澄清,爲什麼我就不能使用隱式轉換:

隱式轉換可能是危險的,當他們在範圍和意外轉換的東西,他們不應該轉換。我總是會顯式地或通過視圖邊界來轉換東西,因爲那樣我就可以控制它,隱式轉換可能會縮小代碼的大小,但也會使其他人難以理解。我只會對'擴展我的圖書館'模式使用隱式轉換。

EDIT2

您可以但是添加到集合類型的方法,做這個轉換,如果這樣的方法在範圍:

trait Convertable[M[A], A] { 
    def convertTo[B](implicit f: A => B): M[B] 
} 

implicit def list2Convertable[A](xs: List[A]) = new Convertable[List, A] { 
    def convertTo[B](implicit f: A => B) = xs.map(f) 
} 

scala> implicit def int2String(x: Int) = x.toString 
int2String: (x: Int)String 

scala> List(1,2,3).convertTo[String] 
res0: List[String] = List(1, 2, 3) 

除了在此處使用其他的隱式轉換,我可能會使用類型類型,但我認爲你有基本的想法。

1

廠開始使用Scala 2.10:

implicit class ListOf[A](val list: List[A]) { 
    def of[B](implicit f: A => B): List[B] = list map f 
} 
implicit def int2String(i: Int) = i.toString 

// Usage 
List(1,2,3).of[String] 
+0

這隻適用於斯卡拉2.10 – mericano1 2013-02-20 09:05:33

+0

是的,它已經出來 – idonnie 2013-02-20 11:20:42

+0

我知道,我只是指出這將是有益的,指出在答案 – mericano1 2013-02-20 13:29:20

-1

在我的代碼,我使用的是改編自托馬斯」的解決方案更廣泛的版本,上述負責處理所有Traversable實例

/** Implicit conversion for Traversable instances where the elements are convertable */ 
implicit def convTrav[S, T, I[S] <: Traversable[S]](input: I[S])(implicit c: S => T): I[T] = 
    (input map c).asInstanceOf[I[T]] 

(這是爲我工作,雖然我很想知道是否有更多經驗豐富的Scala程序員認爲這是一個壞主意,除了通常關於隱式轉換的警告外)