如何在集合内部进行隐式转换?

Jac*_*ack 18 scala

说我有一个隐含的转换:

implicit def aToB(a: A):B={
...
}
Run Code Online (Sandbox Code Playgroud)

如何才能将此隐式转换用于List的元素?

如果我有:

val listOfA: List[A] ...
Run Code Online (Sandbox Code Playgroud)

我有一个带B列表的函数,是否可以让Scala隐式地将所有元素从A转换为B?

如果没有隐式转换,转换可能如下所示:

lisftOfA.map(a => new B(a.someValue, a.anotherValue))
Run Code Online (Sandbox Code Playgroud)

但是,我希望这种情况像'魔术'一样发生......这太难以问了.

Aar*_*rup 16

以下是您可能希望考虑的一些替代方案:

1.使用视图绑定

如果可以更改采用B列表的函数,这将是最简单的解决方案.修改它以接受可以转换为Bs的事物列表.那是,

def yourFn(l: List[B]) = ...
Run Code Online (Sandbox Code Playgroud)

会成为

def yourFn[X <% B](l: List[X]) = ...
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用listOfA调用该函数:

yourFn(listOfA)
Run Code Online (Sandbox Code Playgroud)

2.介绍一种转换方法

这与Rogach的第一个解决方案类似,只是外部转换是非隐式的:

def convert[B, A <% B](l: List[A]): List[B] = l map { a => a: B }
Run Code Online (Sandbox Code Playgroud)

然后在你的函数的调用站点,你会写

yourFn(convert(listOfA))
Run Code Online (Sandbox Code Playgroud)

与Rogach的第二个解决方案一样,这比引入隐式转换更安全一些.

3.引入隐式转换

这相当于Rogach的第一个解决方案,但符号更好(IMO).

implicit def convert[B, A <% B](l: List[A]): List[B] = l map { a => a: B }
Run Code Online (Sandbox Code Playgroud)

如果此转换在您的呼叫站点的范围内,您可以使用listOfA调用您的函数:

yourFn(listOfA)
Run Code Online (Sandbox Code Playgroud)

分手思考

考虑如何以一般方式解决这个问题很有意思.如果我想定义我的转换方法以便它可以处理实现该map方法的任何类型,该怎么办?即

def convert[B, A <% B, C[_]](c: C[A]): C[B] = c map { a => a: B }
Run Code Online (Sandbox Code Playgroud)

当然,这不起作用,因为签名中没有任何内容表达C必须实现的约束map.据我所知,表达这种约束是相当复杂的,不能以一种为任何实现类型提供开箱即用支持的方式来完成map.请参阅类型安全的Scala序列推导.

  • 它被称为*类型归属*.你*将'B`类型归类为'A`类型的对象.这与使用Scala中的`asInstanceOf`方法的*cast*形成对比,因为它在编译时被检查,并且永远不会导致运行时异常. (2认同)