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

6.10 Scala中的标识符

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

字母数字组合标识符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)的值:即没有任何解释的字面量,最差的情况是其甚至出现多次。可能还会在模式匹配中用到常量,在15.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这样的代码会被解析成四个语法符号,等同于 x < - y。而在Scala中,<-会被解析成一个语法符号,所以给出的解析结果是 x <- y。如果你想要的效果是前一种,需要用空格将<和-分开。但这在实际使用中不太会成为问题,因为很少有人会在Java中连着写x<-y而不在中间加上空格或括号。

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

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

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