我想要:
while循环的条件传递,具体来说,我有一个数组,我希望#reject!某些元素来自相当复杂的逻辑.后续调用#reject!可能会删除先前传递中未删除的元素.当#reject!最终停止查找要拒绝的元素时,它将返回nil.此时,我希望循环停止并继续执行程序.
我以为我可以做以下事情:
while array.reject! do |element|
...
end
end
Run Code Online (Sandbox Code Playgroud)
我还没有尝试过它,但是这个构造抛出了vim的ruby语法高亮显示器用于循环(即,它认为第一个do用于while语句,并认为第二个end实际上是封装方法的结束).我也尝试将其重写为while附加到begin...end块的内联修饰符,
begin; end while array.reject! do |element|
...
end
Run Code Online (Sandbox Code Playgroud)
但它仍然以同样的方式搞砸了突出显示.在任何情况下,感觉就像是滥用while循环.
我能想到的唯一方法就是将方法调用指定为proc:
proc = Proc.new do
array.reject! do |element|
...
end
end
while proc.call do; end
Run Code Online (Sandbox Code Playgroud)
虽然有效,但感觉很笨拙,尤其是尾随do; end.
有没有优雅的方法来实现这一目标?
这不仅仅是vim,while array.reject! do |element|语法无效:
$ ruby -c -e 'while array.reject! do |element| end'
-e:1: syntax error, unexpected '|'
while array.reject! do |element| end
^
Run Code Online (Sandbox Code Playgroud)
您可以使用{ ... }而不是do ... end:
while array.reject! { |element|
# ...
}
end
Run Code Online (Sandbox Code Playgroud)
或loop和break:
loop do
break unless array.reject! do |element|
# ...
end
end
Run Code Online (Sandbox Code Playgroud)
更明确一点:
loop do
r = array.reject! do |element|
# ...
end
break unless r
end
Run Code Online (Sandbox Code Playgroud)
Ruby允许您将条件移动到循环语句的末尾.这样可以很容易地将结果存储在循环内部并根据条件检查它:
begin
any_rejected = arr.reject! { … }
end while any_rejected
Run Code Online (Sandbox Code Playgroud)
这可以和做的一样end while arr.reject! { … },但是在这里发生的事情要清楚得多,特别是在复杂的情况下reject!.