首页 文章

Scala:方法\运算符重载

提问于
浏览
33

以下示例来自“Programming in Scala”一书 . 给定一个类'Rational'和以下方法定义:

def add(that: Rational): Rational =
    new Rational(
        this.numer * that.denom + that.numer * this.denom,
        this.denom * that.denom
    )

我可以使用带有Int参数的便捷版本和 makes use of the definition above 成功重载add方法:

def add(that: Int): Rational =
    add(new Rational(that, 1))

到目前为止没问题 .

现在,如果我将方法名称更改为运算符样式名称:

def +(that: Rational): Rational =
    new Rational(
        this.numer * that.denom + that.numer * this.denom,
        this.denom * that.denom
    )

像这样过载:

def +(that: Int): Rational =
    +(new Rational(that, 1))

我得到以下编译错误:

(fragment of Rational.scala):19: error: value unary_+ is not a member of this.Rational
+(new Rational(that, 1))
 ^

为什么编译器要查找 + 方法的一元版本?

3 回答

  • 3

    在Scala中, +x-x~x!x 类型的任何构造都转换为方法调用 x.unary_+ 等 . 这部分是为了允许类似Java的语法将 !b 作为布尔 b 的否定,或 -x 作为否定号码 x .

    因此,代码段 +(new Rational(that, 1)) 被转换为 (new Rational(that,1)).unary_+ ,而 Rational 没有此方法,则会出现编译错误 . 只有当您的函数被调用 +-~! 时,才会出现此错误,因为这些是Scala允许作为一元运算符的唯一字符 . 例如,如果您调用函数 @+ ,则代码编译得很好 .

    虽然,我建议将重写的add函数写为:

    def +(that: Int): Rational =
      this + (new Rational(that, 1))
    

    此代码更好地显示了函数的意图 - 添加一个由整数构成的新 Rational 作为分子, 1 作为分母 this . 这种写法方式被翻译成 this.+(new Rational(that, 1)) ,这就是你想要的 - 在 this 上调用 + 函数 .

    请注意,您可以使用中缀表示法,但调用该函数 . 例如,如果将名称更改回 add ,仍可将定义保持为:

    def add(that: Int): Rational =
      this add (new Rational(that, 1))
    
  • 51

    如果您使用显式 this 调用 + ,它应该可以工作

    def +(that: Int): Rational = this.+(new Rational(that, 1))
    

    Scala允许定义可用于前缀运算符表示法的一元运算符 . 例如,您可以使用 + 作为前缀运算符来实现相同的目的:

    def unary_+: Rational = this.+(new Rational(that, 1))
    val a = new Rational(3,2)
    val b = +a
    

    如果在您的示例中没有显式的 this ,编译器会认为您正在使用未定义的一元运算符 + .

  • 6

    您尚未指定二元运算符,您已指定了一元运算符 .

    所以代替:

    def +(that: Int): Rational =
      +(new Rational(that, 1))
    

    你需要写这个:

    def +(that: Int): Rational =
      this +(new Rational(that, 1))
    

相关问题