Scala:方法\运算符重载

时间:2010-01-02 10:51:21

标签: scala

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

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

我可以使用带有Int参数的便捷版本成功重载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 个答案:

答案 0 :(得分:51)

在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))

答案 1 :(得分:6)

如果您使用明确的+来致电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,编译器认为您使用的是未定义的一元运算符+

答案 2 :(得分:3)

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

所以而不是:

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

你需要写下这个:

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