Scala 如何使隐式转换在集合内工作?
假设我有一个隐式转换:Scala 如何使隐式转换在集合内工作?,scala,Scala,假设我有一个隐式转换: implicit def aToB(a: A):B={ ... } 如何使这种隐式转换在列表的元素上工作 如果我有: val listOfA: List[A] ... 我有一个函数,它接受B的列表,可以让Scala隐式地将所有元素从a转换为B吗 如果没有隐式转换,转换可能如下所示: lisftOfA.map(a => new B(a.someValue, a.anotherValue)) 但我希望这能像“魔法”一样发生。。。这是不是要求太多了。以下是一个通用解
implicit def aToB(a: A):B={
...
}
如何使这种隐式转换在列表的元素上工作
如果我有:
val listOfA: List[A] ...
我有一个函数,它接受B的列表,可以让Scala隐式地将所有元素从a转换为B吗
如果没有隐式转换,转换可能如下所示:
lisftOfA.map(a => new B(a.someValue, a.anotherValue))
但我希望这能像“魔法”一样发生。。。这是不是要求太多了。以下是一个通用解决方案,如果范围内存在隐式转换a=>B,则可以实现列表的隐式转换(列表[a]=>列表[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]
它会更详细一点,但会让您更明确地控制代码。我认为最好的方法是
implicit def asToBs(as: List[A]): List[B] = as map aToB
以下是您可能希望考虑的几个备选方案: 1。使用视图绑定 如果有可能更改接受一个Bs列表的函数,这将是最简单的解决方案。修改它以接受可以转换为Bs的事物列表。就是
def yourFn(l: List[B]) = ...
将成为
def yourFn[X <% B](l: List[X]) = ...
2。介绍一种转换方法
这与Rogach的第一个解决方案类似,只是外部转换是非隐式的:
def convert[B, A <% B](l: List[A]): List[B] = l map { a => a: B }
与Rogach的第二个解决方案一样,这比引入隐式转换要安全一些
3。引入隐式转换
这相当于Rogach的第一个解决方案,但表示法稍微好一点(IMO)
离别的思念
考虑如何用一般的方法来解决这个问题很有趣。如果我想定义转换方法,以便它能够处理实现map
方法的任何类型,该怎么办?i、 e
def convert[B, A <% B, C[_]](c: C[A]): C[B] = c map { a => a: B }
def convert[B,A:B}
当然,这是行不通的,因为签名中没有任何内容表示
C
必须实现map
的约束。据我所知,表示此约束相当复杂,不能以一种为实现map
的任何类型提供开箱即用支持的方式完成。请参阅。完整性,请参阅可能会考虑采用更一般的方法.
该计划:
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
你确定,类型擦除不会有问题吗?@om nom nom-为什么会有问题?隐式在类型擦除之前就解决了。+1我没有遵循这种方法,但这是一个令人耳目一新的简单答案,谢谢。它不起作用。显然列表协方差会混淆编译器。请检查PleaseThaks以获得伟大的示例和解释。首先,我想知道如何在映射中“类型强制转换”,即a=>a:B。有这样做的名称吗?它被称为类型归属。您将类型
B
归因于类型a
的对象。这与强制转换不同,强制转换使用Scala中的作为方法的安装,因为它在编译时被检查,并且永远不能重新启动运行时异常。这似乎不是@JacobusR所要求的。我们希望转换在map
函数中工作,该函数是listOfA
的一个函数。您已经引入了yourFn
,OP没有提到,但我们需要listOfA.map((b:b)=>…)
像convert一样运行(listOfA.map((b:b)=>…)
。似乎只有在我们定义了defyourfn[T](listOfB:List[b),fn:b=>T):List[T]=listOfB.map(fn)时,您的解决方案才会起作用
。也就是说,如果我们包装map
只是为了帮助进行类型推断,这不是我们想要做的。@silasdavis听起来你的问题与OP不同。@JacobusR有一个List[a]
和一个函数,该函数需要一个List[B]
,他想应用到他的List[a]
--我将此函数命名为yourFn
,但是OP在他的问题中引入了它。这是否已成功测试?在中,我显示3.(隐式转换)实际上不起作用。如果可能,请看一看:)这实际上不起作用:val list=list(新a)val listB:list[B]=列表//未编译。请检查
implicit def convert[B, A <% B](l: List[A]): List[B] = l map { a => a: B }
yourFn(listOfA)
def convert[B, A <% B, C[_]](c: C[A]): C[B] = c map { a => a: B }
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, ?)