Scala编程(第4版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

5.4 操作符即方法

Scala给它的基础类型提供了一组丰富的操作符。我们前面的章节也提到过,这些操作符实际上只是普通方法调用的漂亮语法。例如,1 + 2实际上跟1.+(2)是一回事。换句话说,Int类包含了一个名为+的方法,接收一个Int参数,返回Int的结果。这个+方法是在你对两个Int做加法时执行的:

要验证这一点,可以用方法调用的形式显式地写出这个表达式:

事实上,Int包含了多个重载overloaded)的+方法,分别接收不同的参数类型。[3]例如,Int还有另一个也叫+的方法,接收一个Long,返回一个Long。如果你对一个Int加上一个Long,那么后一个+方法会被调用,如:

+符号是一个操作符(更确切地说是一个中缀操作符)。操作符表示法并不局限于那些在其他语言中看上去像操作符的那些方法。可以在操作符表示法中使用任何方法。例如,String类有一个indexOf方法,接收一个Char参数。这个indexOf方法检索字符串中给定字符首次出现的位置,返回位置下标,如果没有找到,则返回-1。你可以像操作符那样使用indexOf

除此之外,String还提供了一个重载的indexOf方法,接收两个参数,分别是要查找的字符和开始检索的下标位置(之前提到的另外那个indexOf方法从下标零开始检索,也就是从String的最开始算起)。虽然这个indexOf方法接收两个参数,但也可以用操作符表示法。不过只要是用操作符表示法来调用多个参数的方法,都必须将这些参数放在圆括号里。以下是展示如何把(两个参数的)indexOf方法当作操作符来使用的例子:

任何方法都可以是操作符

在Scala中,操作符并不是特殊的语法,任何方法都可以是操作符。当你写下“s.indexOf('o')”时,indexOf并不是操作符;但当你写下“s indexOf 'o'”时,indexOf就是操作符了,因为你用的是操作符表示法。

至此,你已经看到了中缀操作符表示法的若干示例,中缀操作符表示法意味着被调用的方法名位于对象和你想传入的参数中间,比如“7 + 2”。Scala还提供了另外两种操作符表示法:前缀和后缀。在前缀表示法中,需要将方法名放在你要调用的方法的对象前面(比如“-7”中的“-”)。在后缀表示法中,需要将方法名放在对象之后(比如“7 toLong”中的“toLong”)。

跟中缀操作符表示法(操作符接收两个操作元,一个在左一个在右)不同,前缀和后缀操作符是一元的unary):它们只接收一个操作元。在前缀表示法中,操作元位于操作符的右侧。前缀操作符的例子有-2.0!found~0xFF等。跟中缀操作符类似,这些前缀操作符也是调用方法的一种简写。不同的是,方法名称是“unary_”加上操作符。举例来说,Scala会把-2.0这样的表达式转换成如下的方法调用:“(2.0).unary_-”。可以自己演示一下,先后用操作符表示法和显式方法调用来完成:

唯一能被用作前缀操作符的是+、-、!和~。因此,如果你定义了一个名为unary_!的方法,可以对满足类型要求的值或变量使用前缀操作符表示法,比如!p。不过如果你定义一个名为unary_*的方法,就不能用前缀操作符表示法了,因为*并不是可以用作前缀操作符的四个标识符之一。可以像正常的方法调用那样调用p.unary_*,但如果你尝试用*p这样的方式来调用,Scala会当作*.p来解析,这大概并不是你想要的效果![4]

后缀操作符是那些不接收参数并且在调用时没有用英文句点圆括号的方法。在Scala中,可以在方法调用时省去空的圆括号。从约定俗成的角度讲,如果方法有副作用的时候保留空的圆括号,比如println();而在方法没有副作用时则可以省掉这组圆括号,比如对String调用toLowerCase时:

在后一种不带参数的场景(无副作用)下,可以选择去掉句点,使用后缀操作符表示法:

在本例中,toLowerCase被当作后缀操作符作用在了操作元s上。

综上所述,要了解Scala基础类型支持的操作符,只需在Scala API文档中查看对应类型声明的方法。不过,由于这是一本Scala教程,我们将在接下来的几节中快速地带你过一遍这些方法当中的大多数。

Java程序员的快速通道

本章剩余部分讲到的Scala知识点跟Java是一致的。如果你是Java大牛,且时间有限,可以安全地跳过,直接进入5.8节,这一节会介绍Scala跟Java在对象相等性方面的不同。