Scala多个隐式转换?

8

我不明白以下代码(Scala 2.9)中的表现看似矛盾的行为:

class Pimp1(val x : Double) {
  def pluss(that : Pimp1) = x + that.x
  def <(that : Pimp1) = x < that.x
}

object Pimp1 {
implicit def d2pimp(d : Double) = new Pimp1(d)
implicit def d2pimp(od : Option[Double]) = new Pimp1(od.get)
} 

object Scratch2 extends App {
    import Pimp1._

    5.0.pluss(Some(5.0))
    5.0 < Some(5.0)
}

代码行 '5.0.pluss(Some(5.0))' 编译通过,但其下一行未能编译成功,报错信息如下:

方法 < 被重载,可用的参数类型为: (x: Double)Boolean (x: Float)Boolean (x: Long)Boolean (x: Int)Boolean (x: Char)Boolean (x: Short)Boolean (x: Byte)Boolean,不能应用于 (Some[Double])

如果我在 Pimp 类中为 Option[Double] 添加显式的 < 操作符:

def <(that : Option[Double]) = x < that.get

一切编译都很好。

现在,根据我对Scala隐式转换规则的理解,这很合理:

  1. 编译器知道Double上没有接受Option[Double]的'<'运算符
  2. 它考虑使用Pimp1进行隐式转换。
  3. 如果Pimp1有适当的运算符,则可以工作,否则会生成错误。
  4. 重要的是,这证明了编译器不考虑应用第二个(可用的)隐式转换,从Option[Double]到Pimp。

这就是我希望的工作方式。

然而,这似乎与第一个示例相矛盾,其中:

  1. 编译器发现Double上没有pluss方法。
  2. 编译器尝试使用Pimp进行隐式转换,该方法确实具有此类方法。
  3. 但是,为了使运算符起作用,编译器必须对参数应用第二个隐式转换,将其转换为Pimp。

根据上面的逻辑,这应该无法编译,但实际上可以。隐式转换规则是否会对不存在的方法和不匹配的方法进行不同处理?


有趣的是,如果你反过来写,它也是正确的:Some(5.0) < 5.0 - Noah
1个回答

5
这对我来说很有意义。第一个方法是这样的:
Double有一个pluss方法吗?没有,我们可以将其隐式转换为具有该方法的内容吗?可以。好的,现在我想应用pluss方法。它接受Option吗?不是。我可以将Option隐式转换为它接受的某些内容吗?是的。
第二个方法是这样的:
Double有一个<方法吗?是的。它接受Option吗?不是。我可以将Option隐式转换为它接受的某些内容吗?不行。

正确。Scala编译器不会尝试为已经具有所需方法的对象查找隐式转换。Option没有比较,因此Some(5.0) < 0是可行的。 - Mikaël Mayer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接