我有以下用例经常出现在我的代码中:
我希望获得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中是否存在这样的特性。
答案 0 :(得分:14)
如果您了解类型,那就非常简单了。第一次从A
隐式转换为B
:
implicit def conversion(a: A): B = //...
然后您需要从List[S]
隐式转换为List[T]
,其中S
和T
是从S
到{{1}的隐式转换的任意类型} exists:
T
这应该有效:
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
而A
为T
。
答案 1 :(得分: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
的实例,并在内部使用它们,就像它们是Bar
一样。
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)
不是在这里使用另一个隐式转换,而是使用类型类代替,但我认为你得到了基本的想法。
答案 2 :(得分: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]
答案 3 :(得分:-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程序员认为这是一个坏主意,除了关于隐式转换的常见警告之外)