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

6.10 Scala中的标识符

至此,你已经看到了Scala中构成标识符的两种最重要的形式:字母数字组合,以及操作符。Scala对于标识符有着非常灵活的规则。除了你见过的这两种,还有另外两种。本节我们将介绍标识符的4种构成形式。

字母数字组合标识符alphanumeric identifier)以字母或下画线开头,可以包含更多的字母、数字或下画线。字符“$”也算作字母;不过,它被预留给那些由Scala编译器生成的标识符。即使能通过编译,用户程序的标识符也不应该包含“$”符号,如果包含了该符号,则会面临与编译器生成的标识符冲撞的风险。

Scala遵循了Java使用驼峰命名法camel-case[5]命名标识符的规则,如toStringHashSet。虽然下画线是合法的标识符,但是它在Scala程序中并不常用,其中一部分原因是与Java保持一致,不过另一个原因是下画线在Scala代码中还有许多其他非标识符的用法。因为上述原因,最好不使用像to_string、__init__或name_这样的标识符。字段、方法参数、局部变量和函数的驼峰命名应该以小写字母开头,如lengthflatMaps等。类和特质的驼峰命名应该以大写字母开头,如BigIntListUnbalancedTreeMap等。[6]

注意

在标识符的末尾使用下画线的一个后果是,如果像这样来声明一个变量——“val name_: Int = 1”,则会得到一个编译错误。编译器会认为要声明的变量名称是“name_:”。要让这段代码通过编译,需要在冒号前额外插入一个空格,就像这样:“val name_ : Int = 1”。

在常量命名上,Scala的习惯与Java不同。在Scala中,常量constant)这个词并不仅仅意味着val。虽然val在初始化之后确实不会变,但它仍然是一个变量。举例来说,方法参数是val,但每次调用方法时,这些val都可以获得不一样的值。而一个常量则更固定。例如,scala.math.Pi被定义成最接近π(即圆周长和直径的比例)的双精度浮点数值。这个值不太可能会变化,因此,Pi显然是一个常量。还可以用常量来表示代码中那些不这样做就会成为魔数magic number)的值:即没有任何解释的字面量,最差的情况是它甚至出现多次。你可能还会在模式匹配中用到常量,在13.2节将介绍一个具体的用例。Java对常量的命名习惯是全大写,并用下画线分隔不同的单词,如MAX_VALUEPI。而Scala的命名习惯是只要求首字母大写。因此,以Java风格命名的常量,如X_OFFSET,在Scala中也可以正常工作,不过Scala通常使用驼峰命名法命名常量,如XOffset

操作标识符operator identifier)由一个或多个操作符构成。操作符指的是那些可以被打印出来的ASCII字符,如+:?~、#等。[7]下面是一些操作标识符举例:

Scala编译器会在内部将操作标识符用内嵌$的方式转换成合法的Java标识符。比如,:->这个操作标识符会在内部表示为$colon$minus$greater。如果你打算从Java代码中访问这些标识符,就需要使用这种内部形式。

由于Scala的操作标识符支持任意长度,因此Java与Scala在这里有一个细微的差异。在Java中,x<-y这样的代码会被解析成4个语法符号,等同于x < - y。而在Scala中,<-会被解析成一个语法符号,所以给出的解析结果是x <- y。如果你想要的效果是前一种,则需要用空格将<-分开。这在实际使用中不太会成为问题,因为很少有人会在Java中连着写x<-y而不在中间加上空格或括号。

混合标识符mixed identifier)由一个字母数字组合标识符、一个下画线和一个操作标识符组成。例如,unary_+表示+操作符的方法名,myvar_=表示赋值的方法名。除此之外,形如myvar_=这样的混合标识符也被Scala编译器用来支持属性(properties),更多内容详见第16章。

字面标识符literal identifier)是用反引号括起来的任意字符串(`...`)。字面标识符举例如下:

可以将任何能被运行时接收的字符串放在反引号中,作为标识符。其结果永远是一个(合法的)Scala标识符。甚至当反引号中的名称是Scala保留字reserved word)时也生效。一个典型的用例是访问Java的Thread类的静态方法yield。不能直接写Thread.yield(),因为yield是Scala的保留字。不过,仍然可以在反引号中使用这个方法名,就像这样:Thread.`yield`()