Scala:方法\运算符重载

jas*_*son 34 scala

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

def add(that: Rational): Rational =
    new Rational(
        this.numer * that.denom + that.numer * this.denom,
        this.denom * that.denom
    )
Run Code Online (Sandbox Code Playgroud)

我可以使用带有Int参数的便捷版本成功地重载add方法,并使用上面的定义:

def add(that: Int): Rational =
    add(new Rational(that, 1))
Run Code Online (Sandbox Code Playgroud)

到目前为止没问题.

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

def +(that: Rational): Rational =
    new Rational(
        this.numer * that.denom + that.numer * this.denom,
        this.denom * that.denom
    )
Run Code Online (Sandbox Code Playgroud)

像这样过载:

def +(that: Int): Rational =
    +(new Rational(that, 1))
Run Code Online (Sandbox Code Playgroud)

我得到以下编译错误:

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

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

Fla*_*gan 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))
Run Code Online (Sandbox Code Playgroud)

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

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

def add(that: Int): Rational =
  this add (new Rational(that, 1))
Run Code Online (Sandbox Code Playgroud)


Mus*_*med 6

如果你+用显式调用this,它应该工作

def +(that: Int): Rational = this.+(new Rational(that, 1))
Run Code Online (Sandbox Code Playgroud)

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

def unary_+: Rational = this.+(new Rational(that, 1))
val a = new Rational(3,2)
val b = +a
Run Code Online (Sandbox Code Playgroud)

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