6
、Syntax Issues
Ruby 的解析器是非常复杂和相对宽松的。它试图理解它看到的东西,而不是强迫程序奴隶般地遵循一套规则。然而,这种行为可能采用了一些习惯。这儿列出了你应该知道的Ruby 语法: l 用于方法调用的圆括号是可选的。这些调用都是有效的: foobar foobar() foobar(a,b,c) foobar a, b, c l 假设圆括号是可选的,x y z 意味着什么,是什么?像它的结果,这意味着, " 调用方法 y ,传递z 做为参数,然后传递结果做为方法x 的参数" 。简单说,它与x(y(z)) 语句的意思一样。 l 让我们试着传递个哈希表给方法: my_method {a=>1, b=>2} 这是个语法错误,因为左花括号被认为是个块的开始,在这种情况下,圆括号是必须的:my_method({a=>1, b=>2}) l 现在让我们假设哈希表是传递给方法的唯一参数。Ruby 非常宽松地允许我们省略花括号: my_method(a=>1, b=>2) 有些人可能认为这看起来像是带有命名参数的方法调用,但是它强调不是这样。 l 现在考虑这个方法调用: foobar.345 看它,有人可能认为foobar 是个对象而345 是个被调用的方法,但明显地方法的名字是不能以数字开头的! 解析器解释它是对方法foobar 的调用,传递数字0.345 做为一个参数。这儿,你看到的是圆括号或中间的空格都被忽略了的结果。不用说,事实上你可以用这种方式编码,但这只是你可的暗示。 l 有些情况下空白也很重要。例如,这些表达式的意思似乎是一样的: x = y + z x = y+z x = y+ z x = y +z 事实上第一到第三个是一样的。然而,在第四种情况中,解析器认为y 是个方法调用,+z 是个传递给它的参数!然后,如果没有名字为y 的方法,它将对这一行给出个错误信息。The moral is to use blank spaces in a reasonable way. l 类似地,x = y*z 是y 和z 的乘法,然而x = y *z 是方法y 的调用,传递一个数组z 的扩展做为参数。 l 在构造标识符时,下划线被认为是小写字母。所以,标识符可以用下划线开头,但它不能是常量即使下一个字母是大写。 l 线性的,如果语句被嵌套,使用关键字elsif 而不像其它语言使用else if 或elif 。 l Ruby 内的关键字不是真正的" 被保留单词" 。在很多情况中,一个关键字可被用于做为一个标识符同时解释器也不会弄混。我们不会说在什么条件下可以或不可以这样做。我们说这些只是认为如果你真的需要的话是可以这做的,警告是这会带来混乱。通常,使用关键字做一个标识符应该小心,应该在你的思想中保持可读性。 l 当然关键字是可选的( 在if 和case 语句中) 。为了可读性当然也可以使用它。对while 和until 循环来说也是一样的。 l 问号和感叹号不是真正的它们可以修改的标识符的一部分,它们应该被认为是后缀。所以,例如尽管chop 和chop! 被认为是不同的标识符,这些字符不允许在其它的地方使用。同样,我们在Ruby 内使用defined? ,但defined 是关键字。 l 在一个字符串内部,英磅符号(#) 被用于表示被计算的表达式。这意味着在很多情况下,当英磅符号出现在一个字符串内时,它必须用反斜线表示法来转义,但是这只在下一个字符是左花括号 ({), 美元符号 ($), 或"at" 符号(@) 时。 l 三元操作符 (? ,它起源于C 语言,在Ruby 中有时也称为" 未文档化的" 。基于这个理由,程序员可以不愿意使用它 ( 尽管我们并不回避它) 。 l 由于事实上问号可以被附加给标识符,所以应该小心要在三元操作符上加上空格。例如,假设我们有变量my_flag ,它即保存true 也可保存false 。然而第一行代码是正确的,而第二行代码将产生语法错误: x = my_flag ? 23 : 45 # OK x = my_flag? 23 : 45 # 语法错误 l The ending marke 用于植入文档的标记 =end 不应该被当成一个记号。它标记完整行;所以,行内的其它字符不会被认为是程序的一部分,但是它们属于被植入的文档。 l Ruby 内的块不是任意的,也就是说,你不能像C 那样凭感觉来开始一个块。块只允许出现在需要它们的地方( 例如,附加给迭代器) 。这也是为什么Ruby 内的post-test 循环使用一个begin-end 对的原因,即使不进行异常处理。 l 记住关键字BEGIN 和END 与begin 和 end 关键字是完全不同的。 l When strings bump together (static concatenation), the concatenation is of a higher precedence than a method call. Here's an example: # These three all give the same result. str1 = "First " 'second'.center(20) str2 = ("First " + 'second').center(20) str3 = "First second".center(20) Precedence is different. l Ruby 有几个伪变量,像起来像局部变量但它们用于特殊目的。它们是self, nil, true, false, __FILE__, 和 __LINE__. 7 、Perspectives in Programming 大概每个人都知道Ruby 在过去曾是个学生或其它语言的用户。这个经历使用学习Ruby 变得较为容易,Ruby 内的许多特性与其它语言内相应特性相似。换句话说,程序员可能被Ruby 内这熟悉的结构带入到一种虚假的安全感觉中,它们会用以前的经验来使用这些结构。 大多数人认为Ruby 来自于Smalltalk, Perl, C/C++, 和其它语言。Their presuppositions and expectations may all vary somewhat, but they will always be present. For this reason, here are a few of the things that some programmers may "trip over" in using Ruby: l 实际上Ruby 内的字符是个整数。它没有自己的类型,也不会被认为是长度为1 的字符串。考虑下面代码片断: x = "Hello" y = ?A print "x[0] = #{ x[0]} n" # Prints: x[0] = 72 print "y = #yn" # Prints: y = 65 if y == "A" # Prints: no print "yesn" else print "non" end l 和其它很多语言一样没有Boolean 类型。TrueClass 和FalseClass 是截然不同的类,它们的实例化是ture 和false 。 Ruby 的很多操作符类似或等同于C 中的。有两个值 得注意的例外是增量减量操作符 (++ 和 --) 。它们在Ruby 中是无效。 l 模数操作符在对待负数上不同的语言有些差别。这种观点的讨论都超出了本书的范围;但可以说Ruby 有下面这样的行为: 5 % 3 # Prints 2 -5 % 3 # Prints 1 5 % -3 # Prints -1 -5 % -3 # Prints 2 l 有些人习惯地认为false 值可以用0 ,空字符串,空字符,或其它东西。但是在Ruby 中,所有东西都是true ;事实上除了false 和nil 每个东西都是true 。 l Ruby 总是反复强调:变量没有类型;只有值才有类型。 l 说变量未被定义( 例如,变量没有声明) 本质与说它是nil 是一样的。这样的值会通过与nil 的等同性测试并且如何在一个条件中单独使用它将计算出false 。这个原则在哈希表中是个例外,因它存储在哈希表中的nil 是有效值,与nil 比较以在哈希表中找是否存在值是不适当的。( 通过方法调用手段,有几个正确的方式可以完成这个比较。) l 记住post-test 循环在Ruby 内可以通过跟随在while 或until 的修饰符形式后面的一个begin-end 结构来模仿。 l 记住Ruby 内没有变量声明。然而,给变量nil 初始值是个好习惯。这的确没有赋给变量类型并且也没有真正地初始化它,但它通知解析器这是个变量的名字而不是一个方法的名字。Ruby 解释一个标识符为一个方法名字,除非它看到早先赋值个名字的引用给变量。 l 记住 ARGV[0] 是命令行的第一个参数,编号自然从零开始;前面提到的参数不是文件或脚本的名字,如C 中的argv[0] 。 l 大多数Ruby 的操作符是真正的方法;这些方法的点形式提供了熟悉和便利。第一个例外是一套反身赋值操作符(+=, -=, *=, 等等) ;第二个例外是下面这些: = .. ... ! not && and || or != !~ l 像大多数( 尽管不是全部) 现代语言,Boolean 操作总是短路;即,Boolean 表达式的计算在它是true 值时停止。在or 操作符序列内,第一个true 将停止求值;在有and 操作符的字符串内,第一个false 将停止求值。 l 记住前缀@@ 用于类变量( 它与类关联而不是实例) 。 l 记住loop 不是关键字;它是一个Kernel 方法,不是一个控制结构。 l 有些人会发觉unless-else 句法有点违反直觉。因为unless 是if 的反面,如果条件为false 则else 子句会被执行。 l 通常传递给方法的参数其实是一个对象的引用;同样,参数有从方法内部被修改的潜在可能。 l 简单的Fixnum 类型被做为直接值传递,所以它不可能在方法内部被修改。true,false 和nil 也是一样。 l 不要混淆&& 和 || 操作符与& 和 | 操作符。它们的用法与C 语言类似;前者用于Boolean 操作,后者用于算术或位操作。 l 这儿是在&&-|| 操作符以及and-or 操作符之间的区别。前者用于更普通的用途,在一个表达内的结果不是true 或false 。后则的结果则总是true 或false ;它们被明确地用于条件内连接Boolean 表达式 ( 所以如果一个表达式不能计算出true 或false 时会有语法错误) 。看下面代码片断: print (false || "string1n") # Prints string1 # print (false or "string2n") # Syntax error! print (true && "string3n") # Prints string3 # print (true and "string4n") # Syntax error! print (true || "string5n") # Prints true # print (true or "string6n") # Syntax error! print (false && "string5n") # Prints false # print (false or "string6n") # Syntax error! l and-or 操作符比&&-|| 操作符有较小优先级。看下面代码片断: a = true b = false c = true d = true a1 = a && b or c && d # &&'s are done first a2 = a && (b or c) && d # or is done first print a1 # Prints false print a2 # Prints true l 另外,要小心赋值操作符有比and 或or 操作符高的优先级!( 反身赋值操作符+=,-= 和其它也是一样的。) 例如,下面代码的第三行看起来像个普通的赋值语句,但它其实是个free-standing 表达式 ( 事实上,等同于第五行。) 。第七行是个真正的赋值语句,它才是程序员真正想要做的: y = false z = true x = y or z # Line 3: = is done BEFORE or! print x, "n" # Prints false (x = y) or z # Line 5: Same as line 3 print x, "n" # Prints false x = (y or z) # Line 7: or is done first print x, "n" # Prints true l 不要混淆对象属性和局部变量。如果你习惯于C++ 或Java ,你可能忘记这一点。变量@my_var 是你写的类的上下文环境内的实例变量( 或属性) ,但是同样环境下的my_var 则只是那个上下文环境内的局部变量。 |
Ruby系列学习资料(四)
最新推荐文章于 2019-04-29 14:38:31 发布