以下示例来自“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))
^
为什么编译器要查找+
方法的一元版本?
答案 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))