6、Array.new(2, Hash.new) # -> [{}, {}] 但是数组中的两个元素是同一个对象,而不是独立的哈希表。要创建包含(独立的)哈希表的数组,请使用“map”或“collect”方法: arr = (1..2).map {Hash.new} 同样,要创建一个数组哈希表,下面的代码可能也达不到目的: hsh = Hash.new([]) while line = gets >if line =~/(/S+)/s+(/S+)/ hsh[$1] << $2 end end puts hsh.length # -> 0 另一个正确且简洁的方法是“(hash[key] ||= []) <<value”,比如 hsh = Hash.new while line = gets if line =~/(/S+)/s+(/S+)/ (hsh[$1] ||= []) << $2 end end
7、使用“可变”对象作为哈希表的键时要小心。要获得期望的结果,在访问哈希表元素前记得调用Hash#rehash。例如: s = "mutable" arr = [s] hsh = { arr => "object" } s.upcase! p hsh[arr] # -> nil (也许不是期望获得的结果) hsh.rehash p hsh[arr] # -> "object"
10、注意区分局部变量和块局部变量在作用域上的区别。如果在一个语句块前局部变量已经被定义,那么语句块将直接使用这个变量(而且很有可能改变这个变量),在这种情况下语句块并不会引入新的作用域。例如: (0..2).each do |i| puts "inside block: i = #{i}" end puts "outside block: i = #{i}" # -> 未定义'i' 另一方面, i = 0 (0..2).each do |i| puts "inside block: i = #{i}" end puts "outside block: i = #{i}" # -> 'outside block: i = 2' 和 j = 0 (0..2).each do |i| j = i end puts "outside block: j = #{j}" # -> 'outside block: j = 2'
11、在Ruby中有两套逻辑运算符:[!,&&,||]和[not,and,or]。[!,&&,||]的优先级高于赋值运算符(=,%=,~=,/=等等),而[not,and,or]的优先级则低于赋值运算符。另外要注意,&&的优先级高于||,而and的优先级则与or相同。举个例子: a = 'test' b = nil both = a && b # both == nil both = a and b # both == 'test' both = (a and b) # both == nil
15、“0..k”代表一个Range对象,而“[0..k]”代表一个数组,这个数组只有一个Range类型的元素。 举个例子,如果 [0..2].each do |i| puts "i = #{i}" end 没有给出你想要的结果,那么你也许应该试试 (0..2).each do |i| puts "i = #{i}" end 或者 0.upto(2) do |i| puts "i = #{i}" end 注意Ruby没有元组(不可变的数组)类型的对象,而括号也经常放在Range对象周围以确保优先级正确(例如上例中“点”运算符强于“点点”运算符)。
17、Ruby中的变量只保存对象的引用,因此使用=运算符时仅复制引用本身。另外,诸如a += b的自赋值也被转换为a = a + b的形式。因此你最好知道某个操作究竟是创建了一个新的对象还是改变了一个已经存在的对象。 例如,string << "another"比string += "another"快(没有创建额外的对象),所以你理所当然应该使用某个类已经定义的更新函数(如果你真的想这么做)。不过,小心“边界效应”,它会影响所有其它引用同一个对象的变量: a = 'aString' c = a a += ' modified using +=' puts c # -> "aString"
a = 'aString' c = a a << ' modified using <<' puts c # -> "aString modified using <<"
19、一般情况下,一个类变量是属于整个继承链而不仅仅是类本身的(比如,一个类变量由父类及其所有派生类所“共享”的)。令人迷惑的是,如果一个子类在其父类之前创建了类变量,那么情况就不同了。例如,如果一个父类首先创建了一个类变量: class Base def initialize @@var = 'base' end
def base_set_var @@var = 'base' end
def base_print_var puts @@var end end
class Derived < Base def initialize super @@var = 'derived' end # notice
def derived_set_var @@var = 'derived' end
def derived_print_var puts @@var end end
d = Derived.new d.base_set_var d.derived_print_var # -> 'base' d.base_print_var # -> 'base' d.derived_set_var d.derived_print_var # -> 'derived' d.base_print_var # -> 'derived' 在上面这段代码中,类变量@@var实际上是被基类和派生类所“共享”的。现在再来看看如果一个子类先创建类变量会发生什么: class Base def initialize @@var = 'base' end
def base_set_var @@var = 'base' end
def base_print_var puts @@var end end
class Derived < Base def initialize @@var = 'derived' super end # changed