Scala的操作符:任何方法都可以是操作符

开发 后端
本文节选自Martin Odersky,Lex Spoon和Bill Venners所著,Regular翻译的《Programming in Scala》的第五章。Scala是一种针对 JVM 将函数和面向对象技术组合在一起的编程语言。

Scala为它的基本类型提供了丰富的操作符集。这些操作符实际只是作用在普通方法调用上华丽的语法。例如,1 + 2与(1).+(2)其实是一回事。换句话说,就是Int类包含了叫做+的方法,它带一个Int参数并返回一个Int结果。这个+方法在两个Int相加时被调用:

51CTO编辑推荐:Scala编程语言专题

  1. scala> val sum = 1 + 2 // Scala调用了(1).+(2)  
  2. sum: Int = 3 
想要证实这点,可以把表达式显式地写成方法调用:

  1. scala> val sumMore = (1).+(2)  
  2. sumMore: Int = 3 
而真正的事实是,Int包含了许多带不同的参数类型的重载:overload的+方法。重载的方法有同样的名称和不同的参数类型。例如,Int还有另一个也叫+的方法参数和返回类型为Long。如果你把Long加到Int上,这个替换的+方法就将被调用:

  1. scala> val longSum = 1 + 2L // Scala调用了(1).+(2L)  
  2. longSum: Long = 3 
符号+是操作符——更明确地说,是中缀操作符。操作符标注不仅限于像+这种其他语言里看上去像操作符一样的东西。你可以把任何方法都当作操作符来标注。例如,类String有一个方法indexOf带一个Char参数。indexOf方法搜索String里***次出现的指定字符,并返回它的索引或-1如果没有找到。你可以把indexOf当作中缀操作符使用,就像这样:

  1. scala> val s = "Hello, world!" 
  2. s: java.lang.String = Hello, world!  
  3. scala> s indexOf 'o' // Scala调用了s.indexOf(’o’)  
  4. res0: Int = 4 
另外,String提供一个重载的indexOf方法,带两个参数,分别是要搜索的字符和从哪个索引开始搜索。(前一个indexOf方法开始于索引零,也就是String开始的地方。)尽管这个indexOf方法带两个参数,你仍然可以用操作符标注的方式使用它。不过当你用操作符标注方式调用带多个参数的方法时,这些参数必须放在括号内。例如,以下是如何把另一种形式的indexOf当作操作符使用的例子(接前例):

  1. scala> s indexOf ('o'5// Scala调用了s.indexOf(’o’, 5)  
  2. res1: Int = 8 
任何方法都可以是操作符

Scala里的操作符不是特殊的语言语法:任何方法都可以是操作符。使用方法的方式使它成为操作符。如果写成s.indexOf('o'),indexOf就不是操作符。不过如果写成,s indexOf 'o',那么indexOf就是操作符了,因为你以操作符标注方式使用它。

目前为止,你已经看到了中缀:infix操作符标注的例子,也就是说调用的方法位于对象和传递给方法的参数或若干参数之间,如“7 + 2”。Scala还有另外两种操作符标注:前缀和后缀。前缀标注中,方法名被放在调用的对象之前,如,-7里的‘-’。后缀标注中,方法放在对象之后,如,“7 toLong”里的“toLong”。

与中缀操作符——操作符带后两个操作数,一个在左一个在右——相反,前缀和后缀操作符都是一元:unary的:它们仅带一个操作数。前缀方式中,操作数在操作符的右边。前缀操作符的例子有-2.0,!found和~0xFF。与中缀操作符一致,这些前缀操作符是在值类型对象上调用方法的简写方式。然而这种情况下,方法名在操作符字符上前缀了“unary_”。例如,Scala会把表达式-2.0转换成方法调用“(2.0).unary_-”。你可以输入通过操作符和显式方法名两种方式对方法的调用来演示这一点:

  1. scala> -2.0             // Scala调用了(2.0).unary_-  
  2. res2: Double = -2.0 
  3. scala> (2.0).unary_-  
  4. res3: Double = -2.0 
可以当作前缀操作符用的标识符只有+,-,!和~。因此,如果你定义了名为unary_!的方法,就可以像!p这样在合适的类型值或变量上用前缀操作符方式调用这个方法。但是如果你定义了名为unary_*的方法,就没办法用成前缀操作符了,因为*不是四种可以当作前缀操作符用的标识符之一。你可以像平常那用调用它,如p.unary_*,但如果尝试像*p这么调用,Scala就会把它理解为*.p,这或许就不会是你想当然的了!然而,不是一点儿希望都没有。仍然有极微弱的机会,让你的带有*p的程序或许能像C++那样被编译。

后缀操作符是不用点或括号调用的不带任何参数的方法。Scala里,你可以舍弃方法调用的空括号。例外就是如果方法带有副作用就加上括号,如println(),不过如果方法没有副作用就可以去掉括号,如String上调用的toLowerCase:

  1. scala> val s = "Hello, world!" 
  2. s: java.lang.String = Hello, world!  
  3. scala> s.toLowerCase  
  4. res4: java.lang.String = hello, world!  
后面的这个例子里,方法没带参数,或者还可以去掉点,采用后缀操作符标注方式:

  1. scala> s toLowerCase  
  2. res5: java.lang.String = hello, world!  
例子里,toLowerCase被当作操作数s上的后缀操作符。

因此要想知道Scala的值类型里你可以用哪些操作符,所有需要做的就是在Scala的API文档里查询定义在值类型上的方法。

【相关阅读】

  1. Scala的基本类型及文本化
  2. Scala程序及其Application特质
  3. Scala程序中的分号推断和Singleton对象
  4. 学习Scala类的定义,字段和方法
  5. 学习Scala脚本:从文件里读取行记录
责任编辑:book05 来源: Artima
相关推荐

2009-07-21 12:47:04

Scala私有字段定义操作符

2009-08-19 17:26:28

C# 操作符

2010-07-14 14:55:07

Perl操作符

2021-10-31 18:59:55

Python操作符用法

2011-04-08 16:26:14

JavaScript

2010-07-19 11:00:24

Perl操作符

2010-07-14 14:30:31

Perl操作符

2009-12-11 10:43:00

Scala讲座操作符函数

2009-09-15 17:16:58

LINQ查询操作符

2012-02-06 09:13:23

LINQ

2009-09-16 09:09:23

Linq Contai

2010-07-14 14:18:51

Perl操作符

2009-07-14 18:34:22

Jython操作符重载

2009-11-30 16:48:08

PHP操作符

2010-07-13 11:11:39

Perl标量

2010-01-28 11:16:28

C++操作符

2009-07-21 09:31:00

Scala数学运算逻辑操作位操作符

2009-07-21 08:41:05

Scala操作符优先级

2016-12-28 09:54:50

AndroidRxJava操作符

2017-01-03 16:12:13

RxJava操作符Android
点赞
收藏

51CTO技术栈公众号