8

我的代码中经常出现以下用例:

  • 收藏[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 中是否存在这样的特性。

4

4 回答 4

14

如果您知道类型,那将非常简单。A从to 的第一个隐式转换B

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

那么你需要隐式转换 from List[S]to List[T]whereS并且是存在隐式转换 from toT的任意类型: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)

在哪里和S是。ATB

于 2013-02-18T17:26:23.257 回答
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)
}

您现在可以创建一个Items带有列表的实例Foo并在内部使用它们,就好像它们是Bars 一样。

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

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

编辑

一些澄清,为什么我不会使用隐式转换:

隐式转换可能很危险,当它们在范围内并意外转换了不应该转换的东西时。我总是会显式地或通过视图边界转换东西,因为这样我就可以控制它,隐式转换也可能会缩小代码的大小,但也会让其他人更难理解。我只会对“扩展我的库”模式使用隐式转换。

编辑2

但是,如果这样的方法在范围内,您可以向集合类型添加一个方法来执行此转换:

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)

我可能不会在这里使用另一个隐式转换,而是使用类型类,但我想你明白了基本的想法。

于 2013-02-18T17:31:07.127 回答
2

从 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]
于 2013-02-18T21:02:10.227 回答
-1

在我的代码中,我使用的是从上面的 Tomasz 解决方案改编的更通用的版本,它处理所有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 程序员认为这是一个坏主意,除了关于隐式转换的常见警告之外)

于 2013-06-07T07:32:18.313 回答