Scala将隐式函数应用于集合

时间:2013-02-28 12:52:42

标签: scala collections implicit

编辑:我正在使用Scala 2.9.2

在Scala中,我定义了一个包装Double的自定义类:

class DoubleWrap( d : Double ) {
    def double( ) = d * 2
}

和从Double到DoubleWrap的隐式转换:

implicit def wrapDouble( d : Double ) = new DoubleWrap( d )

这允许我执行以下操作:

scala> 2.5.double
res0: Double = 5.0

但是,由于Scala中从Int到Double的隐式转换,我还可以执行以下操作:

scala> 2.double
res1: Double = 4.0

此运算符也可以使用map

应用于双类型集合的所有元素
scala> List( 1.0, 2.0, 3.0 ).map( _.double )
res2: List[Double] = List(2.0, 4.0, 6.0)

但是,如果我尝试将该函数应用于整数集合的所有元素,则它不起作用:

scala> List( 1, 2, 3 ).map( _.double )
<console>:10: error: value double is not a member of Int
          List( 1, 2, 3 ).map( _.double )

有谁知道为什么会这样?

2 个答案:

答案 0 :(得分:3)

在scala中,隐式转换是自动链接。换句话说,编译器将寻找允许代码有意义的单个隐式转换,它永远不会尝试应用两个(或更多)连续的隐式转换。

在您的示例中,您可以执行2.double这一事实与DoubleIntPredef的隐式转换无关。 作为证明,请在REPL中尝试:

scala> val i: Int = 2
i: Int = 2

scala> i.double
<console>:13: error: value double is not a member of Int
              i.double

它无法编译。 那么为什么2.double会编译?好问题。 我认为我直观地理解了这一点:2首先可以解释为Int值2或Double值2.0,所以我的直觉是2是在这种情况下,某种程度上已经是Double。 但是,我认为这是错误的,因为即使以下情况也会编译,令人惊讶的是:(2:Int).double(或更奇怪的是:((1+1):Int).double)。老实说,我很惊讶,不知道为什么这会编译而val i: Int = 2; i.double没有。

总而言之,scala不会尝试同时应用两个隐式转换是正常的,但由于某些原因,此规则似乎不适用于常量表达式

现在找到解决问题的方法:只需修改隐式转换,使其接受任何本身可隐式转换为Double的类型。实际上,这允许链接隐式转换:

implicit def wrapDouble[T <% Double]( d : T ) = new DoubleWrap( d )

答案 1 :(得分:0)

这是一个bug,很快就会fixed