发表于:2006.04.03 17:05
分类: Ruby Programmer 2nd
出处:http://my4java.itpub.net/post/9983/65275
---------------------------------------------------------------
第七章 表达式(4-4)
Break, Redo, 和 Next
循环控制结构 break, redo, 和 next 让你可以改变循环或者迭代器的流程。
break 立即结束当前循环;然后跳出去执行循环后面的语句。redo从这次循环体的头开始重新执行,但是不会在对条件进行运算或者从迭代中取下一个值。next跳到本次循环末尾,开始执行下一次循环。
while line = gets
next if line =~ /^s*#/ # skip comments
break if line =~ /^END/ # stop at end
# substitute stuff in backticks and try again
redo if line.gsub!(/`(.*?)`/) { eval($1) }
# process line ...
end
这些关键字也可以用在任何基于迭代器的循环机制中。
i=0
loop do
i += 1
next if i < 3
print i
break if i > 4
end
produces:
345
在Ruby 1.8中,break和next可以接受参数。当在传统的循环中使用时,它或许break and next can be given arguments. When used in conventional loops, it probably makes sense only to do this with break (as any value given to next is effectively lost). If a conventional loop doesn’t execute a break, its value is nil.
result = while line = gets
break(line) if line =~ /answer/
end
process_answer(result) if result
If you want the nitty-gritty detail of how break and next work with blocks and procs, have a look at the reference description starting on page 343. If you are looking for a way of exiting from nested blocks or loops, have a look at Kernel.catch, described on pages 347 and 498.
redo语句使一个循环从当前迭代中重新执行。有时候,你需要从新开始一个循环,retry语句就是个入场卷。它重新开始任何的迭代循环。
for i in 1..100
print "Now at #{i}. Restart? "
retry if gets =~ /^y/i
end
运行这个会话,你可看到
Now at 1. Restart? n
Now at 2. Restart? y
Now at 1. Restart? n
. . .
retry 将重新计算条件值,然后再开始循环。这儿有个例子:
def do_until(cond)
break if cond
yield
retry
end
i = 0
do_until(i > 10) do
print i, " "
i += 1
end
produces:
0 1 2 3 4 5 6 7 8 9 10
变量作用域,循环和块
while,until和for循环内建于Ruby语言之中,没有引入新的作用域,前面定义的局部变量可以在循环中使用,在循环中创建的变量在后面的代码也可以使用。
用于迭代器(如loop和each)的块则有些小区别。通常,在这些块内创建的局部变量是不可以从块的外部访问的。
[ 1, 2, 3 ].each do |x|
y = x + 1
end
[ x, y ]
produces:
prog.rb:4: undefined local variable or method `x' for
main:Object (NameError)
然而,如果block中的变量和前面已经定义的变量重名的话,已经存在的变量将会在块中使用,而在块执行完成后,这个变量的值也会改变。下面的例子显示,它应用了块内通常变量和块的参数两者。
x = nil
y = nil
[ 1, 2, 3 ].each do |x|
y = x + 1
end
[ x, y ] => [3, 4]
注意:这个变量不需要被给出外部作用域的值:Ruby解释器只需要看到它就可以了。
if false
a = 1
end
3.times {|i| a = i }
a => 2
变量作用域和块的观点在Ruby社区中有很大争论。当前的解决方案有一定的问题(明显的是,变量有可能成为块内的变量的别名),但当前还没更好的解决办法。Matz表示在Ruby2.0中会解决这个问题,但在此其间,我们还是有些建议来减少变量和块变量之间冲突。
n 保持你的方法和块尽可能地小。少的变量,可以减少彼此间出现碰撞的机会。也很容易地看到代码中产生冲突的名字。
n 为局部变量和块参数使用不同的命名方案。例如,你或许不想有名为”i”的局部变量,但可以接评受它是个块参数。
实际上,这个问题对你在应用上的思想没有影响。






