4

编辑:我正在使用 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 )

有谁知道为什么会这样?

4

2 回答 2

3

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

在您的示例中,您可以做的事实与从到in2.double的隐式转换这一事实无关。作为证明,在 REPL 中试试这个:DoubleIntPredef

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它已经是 a 。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 )
于 2013-02-28T13:28:55.170 回答
0

这是一个应该很快修复的错误

于 2013-03-08T05:59:52.143 回答