说我有隐式转换:
implicit def aToB(a: A):B={
...
}
如何将此隐式转换用于List的元素?
如果我有:
val listOfA: List[A] ...
我有一个带B列表的函数,是否可以让Scala隐式地将所有元素从A转换为B?
如果没有隐式转换,转换可能如下所示:
lisftOfA.map(a => new B(a.someValue, a.anotherValue))
但是我希望这种情况像“魔术”一样发生......这太难以问了。
答案 0 :(得分:15)
您可能希望考虑以下几种方法:
<强> 1。使用视图绑定
如果可以更改带有B列表的函数,这将是最简单的解决方案。修改它以接受可以转换为Bs的事物列表。也就是说,
def yourFn(l: List[B]) = ...
会变成
def yourFn[X <% B](l: List[X]) = ...
然后,您可以使用listOfA调用该函数:
yourFn(listOfA)
<强> 2。引入转换方法
这与Rogach的第一个解决方案类似,只是外部转换是非隐式的:
def convert[B, A <% B](l: List[A]): List[B] = l map { a => a: B }
然后在你的函数的调用网站上,你会写
yourFn(convert(listOfA))
与Rogach的第二个解决方案一样,这比引入隐式转换更安全。
第3。引入隐式转化
这相当于Rogach的第一个解决方案,但符号更好一些(IMO)。
implicit def convert[B, A <% B](l: List[A]): List[B] = l map { a => a: B }
如果此转换属于您的呼叫站点的范围,您只需使用listOfA调用您的函数:
yourFn(listOfA)
分手思考
考虑如何以一般方式解决这个问题很有意思。如果我想定义转换方法以便它可以处理任何实现map
方法的类型,该怎么办?即,
def convert[B, A <% B, C[_]](c: C[A]): C[B] = c map { a => a: B }
当然,这不起作用,因为签名中没有任何内容表示C
必须实施的约束map
。据我所知,表达此约束是相当复杂的,不能以为实现map
的任何类型提供开箱即用支持的方式完成。请参阅Type-safe Scala sequence comprehensions。
答案 1 :(得分:4)
以下是一般解决方案,如果隐式转换A =&gt; B在范围内可用,则启用列表的隐式转换(列表[A] =&gt;列表[B]):
scala> class A
defined class A
scala> class B
defined class B
scala> implicit def a2b(a:A) = new B
a2b: (a: A)B
scala> implicit def mapI[A,B](l: List[A])(implicit conv: A => B): List[B] = l.map(conv)
mapI: [A, B](l: List[A])(implicit conv: (A) => B)List[B]
scala> List(new A): List[B]
res0: List[B] = List(B@efa0bf4)
这是你需要的吗?
此外,由于您已经进行了隐式转换,因此您只需编写:
listOfA.map(a2b) // List[B]
它会更冗长,但会让您更加明确地控制代码。
答案 2 :(得分:3)
我认为最好的可能是
implicit def asToBs(as: List[A]): List[B] = as map aToB
答案 3 :(得分:1)
为了完整起见,您可能希望考虑使用CanBuildFrom
的更通用的方法。
这个程序:
import scala.collection.generic.CanBuildFrom
import scala.language.{higherKinds, implicitConversions}
implicit def implyConvertedTraversable[A, B, C[X] <: Traversable[X]](as: C[A])(implicit conversion: A => B, cbf: CanBuildFrom[C[A], B, C[B]]): C[B] = {
val builder = cbf(as)
builder.sizeHint(as)
builder ++= as.map(conversion)
builder.result()
}
implicit def implyString(a: Int): String = a.toString
val intList = List(1, 2, 3)
val intStream = Stream(1, 2, 3)
val stringList: List[String] = intList
val stringStream: Stream[String] = intStream
收率:
intList: List[Int] = List(1, 2, 3)
intStream: scala.collection.immutable.Stream[Int] = Stream(1, ?)
stringList: List[String] = List(1, 2, 3)
stringStream: Stream[String] = Stream(1, ?)