为什么scala需要`unary_`前缀?

jha*_*ott 26 scala

初学者斯卡拉问题,但我在这里找不到答案.

与C++中的重载类似,我希望编译器可以区分一个名为-一个参数的方法(与类相同的类型)和一个-不带参数的一元版本,为什么unary_需要呢?

Jör*_*tag 72

一元前缀运算符unary_前缀有点误导:它更多地是关于前缀部分而不是一元部分.你需要一些方法来区分

!foo // unary prefix !
Run Code Online (Sandbox Code Playgroud)

foo! // unary postfix !
Run Code Online (Sandbox Code Playgroud)

记住:Scala实际上没有运算符.调用方法有两种方法,使用.或使用空格:

foo.bar(1, "two")
foo bar(1, "two")
Run Code Online (Sandbox Code Playgroud)

当你有一个参数时,你可以不用括号:

foo plus(1)
foo plus 1
Run Code Online (Sandbox Code Playgroud)

最后,(几乎)任何字符在标识符中都是合法的:

foo plus 1
foo + 1
Run Code Online (Sandbox Code Playgroud)

现在看起来 Scala有一个二进制中缀+运算符,但它实际上没有.它只是一个用普通方法调用语法调用的普通方法.

然而,我上面所说的并不完全正确.如果Scala不支持运算符,那么这只是正常的方法调用

2 + 3 * 4
Run Code Online (Sandbox Code Playgroud)

将评估为20(例如在Smalltalk,Self和Newspeak中),而不是14.因此,Scala中的运算符有一点点支持(实际上是两个小位).当使用空格(所谓的"运算符语法")而不是方法调用.方法时,该方法以运算符字符开头,那么Scala将尊重运算符优先级.

和运营商的支持其它有点是,有一些运营商,你会希望有,但不能简单地表示为方法调用.它适用于二进制中缀运算符和一元后缀运算符:

foo op bar // same as:
foo.op(bar)

foo op     // same as:
foo.op
Run Code Online (Sandbox Code Playgroud)

但不是前缀或"around-fix"运算符:

!foo
foo(bar)
Run Code Online (Sandbox Code Playgroud)

因此,有一些特殊的语法糖转换规则:

!foo
foo.unary_!
// same for +, - and ~

foo(bar)
foo.apply(bar)

foo(bar) = 1
foo.update(bar, 1)

foo += 1
foo.+=(1) // but if this doesn't compile, then the compiler will also try
foo = foo.+(1)
Run Code Online (Sandbox Code Playgroud)

并且在方法名称中需要在字母数字和"运算符"部分之间加下划线的原因是因为您不知道是否

foo!
Run Code Online (Sandbox Code Playgroud)

手段

foo.!
Run Code Online (Sandbox Code Playgroud)

要么

this.foo!
Run Code Online (Sandbox Code Playgroud)

因此,foo!由于方法名称是非法的,因此需要调用它foo_!.

  • 感谢您的详细解释和其他见解:) (5认同)

dre*_*xin 9

因为在scala中创建一个名为的方法是完全-没有问题的,它不带参数.你如何区分普通方法和一元方法?例如,!与一元修复运算符具有完全不同的含义.