假设您想要将一些方法添加到所有智能类型。这可以是这样的:在Scala中隐式转换泛型和非泛型子类型
import collection.generic.CanBuildFrom
class Foo[P, S[X] <: Iterable[X]](val s : S[P]) {
def bar(j : P)(implicit bf : CanBuildFrom[S[P],P,S[P]]) : S[P] = {
val builder = bf(s)
builder ++= s
builder += j
builder.result
}
def oneBar(j : P)(implicit bf : CanBuildFrom[S[P],P,S[P]]) : P = bar(j).head
}
implicit def iter2foo[P, S[X] <: Iterable[X]](s : S[P]) = new Foo[P,S](s)
现在,类似的代码
println(Seq(1,2,3,4) bar 5)
编译和执行顺利。然而,
println((1 to 4) bar 5)
导致
error: value bar is not a member of scala.collection.immutable.Range.Inclusive
with scala.collection.immutable.Range.ByOne
我想这可能是因为隐式转换需求(?)是参数的类型有一个类型参数(Range
还没有)。但是
implicit def iter2foo[P, S <: Iterable[P]](s : S) = new Foo[P,Iterable](s)
不会改变任何东西。请注意0延伸Iterable[Int]
。
我在做什么错?我怎样才能写出一个适用于所有Iterable
的子类型的隐式转换?
编辑:我只是注意到按预期(上REPL)更简单
implicit def iter2foo[P](s : Iterable[P]) = new Foo[P,Iterable](s)
作品。还是呢?这种解决方案有什么缺点吗?
编辑2:的缺点是的bar
静态结果类型只会Iterable[P]
,而不是更具体的类型。虽然构建的集合具有正确的(实际)类型。
它不应该为'String'工作(因为它是唯一可见的是'Seq'),但它应该'Map','范围“和其他可怜的生物。如果这是一个问题,为什么第二个版本不起作用?我怎样才能定义第二个隐式转换,它捕获所有不带类型参数的'Iterable'的子类型? – Raphael 2011-03-03 18:04:19
@update:我明白了。然而,我不清楚为什么推理者不考虑超类型。由于你不能用不同的参数(?)扩展相同的特征,这应该产生明确的结果。至于我更简单的版本,它创建了正确的(动态)类型的集合,但只能静态地输入“Iterable”。那就是你得到'CanBuildFrom'的“底层”优势,但不是打字优势。 – Raphael 2011-03-04 11:13:41
我已经扩展了我的答案,以更详细地解释。 – 2011-03-04 11:36:27