编辑:我正在使用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 )
有谁知道为什么会这样?
答案 0 :(得分:3)
在scala中,隐式转换是不自动链接。换句话说,编译器将寻找允许代码有意义的单个隐式转换,它永远不会尝试应用两个(或更多)连续的隐式转换。
在您的示例中,您可以执行2.double
这一事实与Double
中Int
到Predef
的隐式转换无关。
作为证明,请在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)