【发布时间】:2012-04-15 05:22:44
【问题描述】:
由于缺少更好的示例,假设我定义了一个容器类型,它采用单个类型参数。假设这个容器包装了一个相同类型的 List。我想在我的新容器上定义一个方法,这样每当执行操作时,它都会将调用委托给嵌入列表,但它会返回我的容器类型作为结果(可能是不同的类型参数)。为此,我将使用 scala 集合中的隐式构建器模式。这是基本结构:
class Foo[A](val data: List[A]) {
def foo[C, That](pf: PartialFunction[A, C])(
implicit bf: CanBuildFrom[Foo[_], C, That]
): That = {
bf(new Foo(data.collect(pf))).result
}
}
object Foo {
def newBuilder[A]: Builder[A, Foo[A]] =
new ArrayBuffer[A] mapResult { r => new Foo(r.toList) }
implicit def canBuildFrom[A]: CanBuildFrom[Foo[_], A, Foo[A]] =
new CanBuildFrom[Foo[_], A, Foo[A]] {
def apply(from: Foo[_]) = newBuilder
def apply() = newBuilder
}
}
因此,当我的 pf 从 Int 转换为 String 时,我期望返回 Foo[String]:
scala> val f = new Foo(List(1,2,3))
f: Foo[Int] = Foo@15172301
scala> f.foo { case x => x.toString }
res318: Foo[java.lang.String] = Foo@6ff763fa
虽然前面的示例基于 CanBuildFrom,它采用 Foo[_] 的“from”类型、“A”的元素类型,并转换为“Foo[A]”的“to”类型。我想做的是采用 List[_] 的 'from' 类型,'A' 的元素类型,并转换为 'Foo[A]' 的 'to' 类型。大致如下:
class Foo[A](val data: List[A]) {
def foo[C, That](pf: PartialFunction[A, C])(
implicit bf: CanBuildFrom[List[_], C, That]
): That = {
data.collect(pf)(bf)
}
}
object Foo {
def newBuilder[A]: Builder[A, Foo[A]] =
new ArrayBuffer[A] mapResult { r => new Foo(r.toList) }
implicit def canBuildFrom[A]: CanBuildFrom[List[_], A, Foo[A]] =
new CanBuildFrom[List[_], A, Foo[A]] {
def apply(from: List[_]) = newBuilder
def apply() = newBuilder
}
}
在这里,我将隐式 CanBuildFrom 参数直接传递给 List 类,以便它可以构建我的 Foo 类来存储结果。但是,当我运行相同的测试时,我没有得到 Foo[String],而是得到一个列表[字符串]。换句话说,它不是使用我的隐式,而是使用通用版本。
scala> val f = new Foo(List(1,2,3))
f: Foo[Int] = Foo@236f7a59
scala> f.foo { case x => x.toString }
res319: List[java.lang.String] = List(1, 2, 3)
那么,我的问题是为什么?我会认为,如果我当前的类型是 Foo 并且我正在转换为 Foo 并且范围内有一个隐式 fn 匹配输入参数类型(在本例中为 List ),那么这将是最佳匹配。我做错了什么还是出于安全原因,“来自”集合在选择转换为哪个集合时具有最高优先级。我可以做些什么来提高我的隐含优先级吗?
【问题讨论】:
标签: scala collections implicit