块的语法结构
块是不能单独存在的,它必须出现在方法调用之后,也就是说如果块不在一个迭代器或者方法调用中没有yield那么这个块会被忽略。块以{}定义,或者使用do end 关键字,块的一个花括号{ 或者do 关键字必须与迭代器或者方法调用在同一行,否则Ruby解析器无法把它当作迭代器或者方法调用的一部分:
# 打印1到10的数字
1.upto(10) {|x| puts x } # 块与方法调用位于同一行 1.upto(10) do |x| # 使用 do/end关键字 puts x end 1.upto(10) # 没有指定块
{|x| puts x } # 语法错误:块没有位于方法调用之后一个通常的做法是,如果块只有一行接单的逻辑则使用{},如果是多行的逻辑,就使用do/end关键字方式。值得一提的是如果你的方法存在参数,那么使用{的时候要给参数加上括号(),如果你的参数没有括号,那么你应该使用do/end方式:
1.upto(3) {|x| puts x } # 加括号的参数使用{} 1.upto 3 do |x| puts x end # 没有括号参数的方法使用,do/end 1.upto 3 {|x| puts x } # 语法错误!块可以有参数,不过它的参数要放在||之间并用逗号分隔,除此之外它和方法参数非常相似:
# 字典对象的each方法有两个参数 hash.each do |key, value| # 循环调用字典对象的(key,value) puts "#{key}: #{value}" # 打印key和value end # 块结束块的返回值
我们在前面提到的块调用中一再说到yield值,但是没有说到返回值,实际上块是有返回值的,返回值就是块的最后一个表达式的值,注意,不要在块中使用return关键字,这个关键字意味着强制结束你的块逻辑执行,有些时候这是不好的,如果你希望块能够返回更多的值你应该使用next关键字:
array.collect do |x| next 0 if x == nil # 如果x==nil返回0 next x, x*x # 返回两个值 end块的变量范围
块内可以有自己的局部变量,这些变量只在块的范围你有效,但是,如果块内的变量名和块外的变量名相同,这时Ruby不会在块内重新声明变量,而是使用块外部的变量。有时候这对我们来说是很有用的,比如:
total = 0 data.each {|x| total += x } # 计算数组内所有元素的合计值 puts total # 打印合计值但是有的时候这样不好,比如,如果一个块的参数和一个已经存在的变量重名,那么Ruby不会创建一个新的变量而是使用那个已经存在的变量。比如:
1.upto(10) do |i| # 十条记录 1.upto(10) do |i| # 每条记录有十列 print "#{i} " # 打印每一列
end print " ==> Row #{i}\n" # 这里试图打印行号,但是实际得到是列号 end在Ruby1.9中没有这种情况,块中的变量只在当前块中有效,而且不共享块以为定义的变量,如果你打开了-w选项,Ruby会警告你块变量与已经存在的变量重复。Ruby1.9中从语法定义上根本的解决了这个问题,块参数之间使用分号;分隔来表示这是一个块的参数:
x = y = 0 # 局部变量
1.upto(4) do |x;y| # x和y现在是块的局部变量 y = x + 1 # 使用块局部变量
puts y*y # 打印4, 9, 16, 25 end [x,y] # => [0,0]:块没有修改外部的局部变量块可以有多个参数和多个变量下面是一个例子:
hash.each {|key,value; i,j,k| ... }
No comments:
Post a Comment