第三章 字句构造与表达式
第一节 标识符与字面值
在前面一章的常量和变量两个部分中,已经初步的感性接触了一下Ruby的标识,像常量和变量的名字都是Ruby的标识符。在Ruby中,标识符就是以字母或下划线开头、其后允许跟字母、数字或下划线的一个符号。它没有长度的限制,例如: _66RPG Sail_Cat bluefooldog 这些都可以作为Ruby的合法标识符。 无论你把标识符写的多么花哨,它终究只是一个代号而已,真正承载的有意义的是它内部所代表的东西。比如你令常量A = 1,那么当你在脚本中调用常量的名字A的时候,你所想到的其实是它的内在值1。 所以,再复杂的脚本程序,如果仅仅只有标识符而没有实际值的话,是没有任何意义的。而一个值要参与脚本的运算,它的第一次露面,必然是以字面值的形式。所谓字面值,就是你可以一目了然的看出它是一个什么样的值,就像数字1和字符串"Hello World"那样,在程序中直接描述,不通过标识符来进行引用的值。 Ruby中大多数数据类型的字面值都是比较好理解的: 数字型字面值,分整数、浮点数和非十进制数三种,而每种又可以再细划分: 整数: 无符号整数:0 1 4 8 即不带符号,不带小数点的0-9任意组合 有符号整数:-2 +4 -5 即以正负号开头加上后面0-9任意组合 浮点数: 一般表示法:4.5 -20.0 0.375 即带有小数点,并且小数点后至少有一位的数字组合 科学计数法:1.5e+2 -2.0e-3 即用一个带有小数点的部分用为真数,后跟e,再跟一个有符号整数作为指数的组合 注意:绝对值在0-1之间的浮点数,不可以省略小数点前面的0,比如0.375不能够写成.375,另外,如果小数点前后的0实在太多,建议采用科学计数法的写法。1.5e+2表示1.5乘以10的2次方,也就是150。 若要将一个整数强制表示为浮点数,根据浮点数的书写规则在后面添加.0就可以了。 非十进制数(所有的非十进制数都是整数): 二进制:0b0011 0b10111 即用0b开头加上后面0-1的任意组合 八进制:0o377 0o422160 即用0o开头加上后面0-7的任意组合 十六进制:0x3FF 0x55AA 即用0x开头加上后面0-9 A-F的任意组合 顺带说一下,十进制数可以写成0d开头加上后面0-9的任意组合的形式,不过这样似乎没有必要。 有时为了方便起见,可以在数字字面值中插入下划线作为分隔符,以方便阅读,例如10000000000可以写成10_000_000_000,0xFF7B432C可以写成0xFF7B_432C。但是需要注意,下划线不能插在字面值的开头或结尾,亦不能连续插入多个下划线。 字符串字面值,也分一般字符串和正规字符串两种形式: 一般字符串:"Hello World" '66RPG 梦想世界 在你手中' 即头尾用双引号或单引号括起来的一串任意的字母、数字、符号甚至是汉字的文本 当字符串中需要包括双引号或单引号本身时,可以用另外一组引号将其括起来。当字符串中需要同时包括双引号或单引号时,可使用下面的特殊字符: 特殊字符就是一些难于直接写出的控制符号,比如回车、换行、换页等,或者是扩展字符集中的符号。主要有以下几个: \t 表示Tab(跳格) \n 表示换行 \r 表示回车 \f 表示换页 \s 表示空格 \nnn 字符的ASCII代码(八进制),nnn为000-377的任意八进制数 \xnn 字符的ASCII代码(十六进制),nn为00-FF的任意十六进制数 \\ 表示\这个字符本身,以免引起混淆 查到双引号的ASCII代码为22,那么就可以用\x22或\042表示,单引号的表示方法为\x27或\47 不过,单引号和双引号,用作字符串的标志,其功能会有细微的差别,这点会在下一节“表达式”的部分中详细解说。 正规字符串:/Ruby is good/ /cissy/i 即头尾用正斜杠括起来的文本,不过在字符串后面可以附加一个匹配信息: i 忽略大小写 m 标识多行的正规字符串 o 只处理一次内嵌表达式(下节详述) x 将分行写的正规字符串并成一行,并忽略注释信息 正规字符串一般是用于字符串的查找、匹配和替换,它当中有相当多特殊作用的字符组合,因此它一般也被称作正规表达式。 最基本的字面值就是这两个,其他数据类型的字面值,虽然有的相当复杂,但或多或少都是建立在这两个的组合的基础上。不过有几类是特殊的(它们实际上并不是字面值,而是特殊性质的标识符,但由于写法上是惟一的,所以在程序中就等同于字面值的功能): 空白类字面值:只有 nil 作为空白类惟一的实例,它是用关键字来作为字面值的,表示空 布尔型字面值:true 和 false 分别作为TrueClass和FalseClass惟一的实例,以关键字来作为字面值,表示真或者假 其他较复杂类型的数据的字面值,会在以后讲解到这些数据类型时再进行介绍。 介绍了标识符和字面值以后,下面我们就要进入Ruby的功能版块,这将是任何计算机语言最精彩也是最重要的部分:表达式
第二节 表达式
“表达式”,是对能够实现一个基本功能单位的语句的总称。小到独立的一个常量,一个变量,一个字面值,大到一个完整的控制结构,都统成为Ruby的表达式。 表达式,按照组成的不同,分为几种。这几种之间可以形成包容和嵌套的关系,因此我们从最简单最基本的开始介绍: 真值表达式:它是指一个没有任何参照和运算就直接表示出值的表达式 表达式构造:常量 或 变量 或 字面值 或者更严谨的说法是:标识符 或 字面值 例如: SailCat 这是一个常量表达式 bluefool 这是一个变量表达式 66 这是一个字面值 运算表达式:它是指一个经过运算以后得出一个值的表达式 表达式构造:真值表达式 运算符 真值表达式 [运算符 真值表达式 [运算符 真值表达式 [……]]] 这是一个可以无限扩展嵌套下去的表达式类型。 例如: 1 * 5 用运算符 * 连接数字 1 和 5 "Hello" + 'World' 用运算符 + 连接字符串 Hello 和 World bluefool | @_66RPG 用运算符 | 连接一般变量bluefool 和 类变量 _66RPG 运算符分很多种,最主要的有数值运算符、字符运算符、比较运算符、逻辑运算符、自运算符和分歧运算符。 数值运算符:就是我们一般算算术用的:+(加)、-(减)、*(乘)、/(除)、%(求余)、**(乘方)、+(正)、-(负) 例: 1 + 2 得出的值是 3 12 - 5 * -2 得出的值是 22,这个例子说法运算符是有优先级的,和我们习惯的优先级一样 2 ** (2 * 5) 得出的值是 1024,这个例子说明,用括号可以强制改变运算符的优先级,这和我们习惯的算式也是一样的 + 和 - 两个运算符,用作正负的意义时,是单目运算符。所谓单目运算符就是指左边不能带表达式的运算符,表达式只能接在其右边。 字符运算符:+(连接)和*(重复) 例: "SailCat" + " is a cat." 得出的值是字符串 SailCat is a cat. '66RPG' * 2 得出的值是字符串 66RPG66RPG 比较运算符:==(等于)、!=(不等于)、<(小于)、>(大于)、<=(小于等于)、>=(大于等于) 注意这些运算符中有4个和我们的习惯写法不一样,书写程序时要引起注意 比较运算符会比较两个表达式各自的值,按照成立与否,得出true或false的结论 例: 6 > 5 得出true 6 == 5 得出false "SailCat" > "bluefool" 得出false 通常来说,只有数值和字符串是可以比较的,其他的一般都不可以。 逻辑运算符:and(与)、or(或)、not(非)。另外,&& || !这三个运算符和前面三个一样,但拥有更高的优先级。 逻辑运算符是用来对布尔型数据(真假数据)进行操作的。除了not是给出和原先相反的值以外,其它的都是依据运算符两边的真假情况下得出特定的值。 and: 如果左边是false,则得出false,否则得出右边的值 or: 如果左边是true,则得出true,否则得出右边的值 not: 如果右边是true,则得出false,否则得出true not是一个单目运算符。和前面提到的+(正)、-(负)一样,左边不能带有表达式。 例: false and true 得出false true or false 得出true not true 得出false 当然,由于运算表达式嵌套扩展的特性,实际应用中当然不会这样单调。 6 > 5 or 6 < 1 得出 true 自运算符:这实际上是变相的赋值运算,在后面的“赋值表达式”中提到。 分歧运算符:这实际上是一个选择结构,它是一个三目运算符,构造是: 布尔值 ? 表达式1 : 表达式2 当布尔值为true时,得到表达式1的结果,否则得到表达式2的结果。 方法表达式:它是将一个表达式的值代入一个方法后计算再得出结果的表达式 表达式构造:方法标识符[(表达式1, [表达式2, [表达式3……]])] 表达式1往后,包在括号里的部分称为“参数”,它们是方法运算所需要的值。参数的个数取决于方法定义时所要求的个数,如果方法不要求参数,那么包括括号在内的部分全部省略。 例如: load_data($data_scripts, "/Data/Scripts.rxdata") eval("p 'you lose'") 赋值表达式:它是将一个表达式的结果赋给一个标识符(常量或变量)的表达式 表达式构造:标识符 = 真值表达式 或 运算表达式 或 方法表达式 例如: Max_Damage = 9999 info = "SailCat is" + " here." slope = Math.tan(3.14) 另一种构造方法:标识符 自运算符 真值表达式 或 运算表达式 或 方法表达式 它的意义相当于:标识符 = 标识符 自运算 后续表达式 例如: info = "SailCat is" info += " here." 这个就和上面的第二个表达式相同了。 自运算符和一般运算符基本上是一一对应的,自运算符的写法是在原先的运算符后面加上=,一共有这么几个: 数值自运算:+= -= *= /= %= **= 字符自运算:+= *= 逻辑自运算:&= |= 由于比较表达式的特性,没有比较自运算。 单目表达式没有自运算,原因很明显,它不能把自己代入表达式进行计算。 结构表达式:这是最复杂的一类表达式,它完成一个完整的定义或控制的功能。 表达式构造:结构控制表达式(保留字 [其他表达式])[表达式组群] end 例如: if a == 2 then p 2 else p 3 end while m < 4 m += 1 end def orochi2k p "-_-!" end 虽然结构表达式可以千变万化,但惟一共同的特点就是它们全部都以end来结束。 这些不同的结构,将会在以后的章节中逐渐涉及。 内嵌表达式:这是一种很特殊的表达式,它是将一个表达式显式的写入一个字符串字面值中,在读取字符串字面值的时候计算这个表达式。 只有双引号括起的字符串和正规字符串可以使用内嵌表达式,单引号的不能使用。 表达式构造:"字面值……#{内嵌表达式}……字面值" /字面值……#{内嵌表达式}……字面值/ 例如: a = "cat" b = "dog" print "SailCat is a #{a}." print /bluefool is a #{b}./ 这样,输出显示的值将分别是字符串 SailCat is a cat. 和 bluefool is a dog. 但如果写成单引号的形式,比如: print 'SailCat is a #{a}.' 则输出为 SailCat is a #{a}.,内嵌表达式失效。 此外,前面提到过的特殊控制符,也只能在双引号的字符串中使用。 以上这些基本上就涵盖了Ruby中的表达式,而表达式之所以被称为表达式,是因为它们具有一个共同的属性:返回值。任何表达式都有一个返回值,没有例外。 对于真值表达式,返回值就是所表示的值本身; 对于运算表达式,返回值就是运算的结果; 对于方法表达式,返回值就是方法执行的结果,所以方法表达式有时也称作函数表达式; 对于赋值表达式,返回值是被赋值的那个标识符的值; 对于结构表达式,返回值一般是nil,也可能是结构结束前(end以前)所执行的最后一个表达式的返回值。虽然这个返回值基本上没有什么实际用途,但它仍然是存在的。 可以用p或print来测试显示表达式的返回值,这也是上面提到的几个例子中用的方法。
第三节 字句构造
Ruby的字句构造法实在是非常简单: 分行法: [# 注释] 表达式 表达式 表达式 …… 同行法: 表达式; 表达式; 表达式; …… [# 注释] 续行法: 表达\ 式 [# 注释] 表达\ 式 …… 除此之外,再无其他的字句构造法。Ruby的Syntax就到此为止了。不过这么玄的东西,不解释一下好像说不过去…… 分行法:是用的最多的一种程序书写法,每一行是一个独立的表达式基本单位。 例如: a = 1 a += 2 p a 同行法:在行数受到限制时,可以将一些简短的表达式合并到同一行内,之间用分号隔开。 例如: a = 1; a += 2; p a 续行法:在列数受到限制时,可以将一些较长的表达式写在多行里,但是要保证表达式中的每一个子表达式都是完整的。 例如: a = 1 a +=\ 2 p a 注释:这不是一个必须的部分,Ruby的程序中,只要不是在字符串里,任何地方出现了 字符#,其后的所有部分都会被认为是注释,注释不会被执行。所以一般可以用来说明程序的功能,或屏蔽掉一些语句用于调试。 例: # 这一行是注释 p 3 # 输出3,这里是注释 #p 3 这一行不会被执行 在以后编写较大规模的Ruby程序时,适时的加入注释是一个良好的习惯,方便后期的调试与修改。 无比琐碎而枯燥的一章,但是也彻底讲清了Ruby语言最基本的结构。因为讲的都是很基本的东西,所以就没有必要给出范例工程了。知道了Ruby语言的基本构造以后,下面我们就要进入真正的实战。请看:我的第一个Ruby程序。
|