我想:
while
循环的条件传递,具体来说,我有一个数组,我想#reject!
基于相当复杂的逻辑的某些元素。对#reject!
的后续调用可能会删除之前传递中未删除的元素。当#reject!
最终停止查找要拒绝的元素时,它将返回nil
。此时,我希望循环停止并继续执行程序。
我以为我可以做到以下几点:
while array.reject! do |element|
...
end
end
我还没有真正尝试过,但是这个结构会抛出vim的ruby语法高亮显示一个循环(即它认为第一个do
是while
语句,并认为第二个end
实际上是封装方法的结束。我还尝试将其重写为附加到while
块的内联begin...end
修饰符,
begin; end while array.reject! do |element|
...
end
但它仍然以同样的方式搞砸了突出显示。无论如何,感觉就像滥用while
循环一样。
我能想到的唯一方法就是将方法调用指定为proc:
proc = Proc.new do
array.reject! do |element|
...
end
end
while proc.call do; end
虽然有效,但感觉很笨拙,尤其是尾随do; end
。
有没有优雅的方法来实现这个目标?
答案 0 :(得分:5)
这不仅仅是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
^
您可以使用{ ... }
代替do ... end
:
while array.reject! { |element|
# ...
}
end
或loop
和break
:
loop do
break unless array.reject! do |element|
# ...
end
end
更明确一点:
loop do
r = array.reject! do |element|
# ...
end
break unless r
end
答案 1 :(得分:5)
Ruby允许您将条件移动到循环语句的末尾。这样可以很容易地将结果存储在循环内部并根据条件进行检查:
begin
any_rejected = arr.reject! { … }
end while any_rejected
这与执行end while arr.reject! { … }
的工作方式相同,但在这里发生的事情要清楚得多,特别是对于复杂的reject!
。
答案 2 :(得分:2)
你是对的,Ruby解析器认为FEED_STORAGES = {
'': 'path.to.CustomFileFeedStorage',
'file': 'path.to.CustomFileFeedStorage',
}
属于do
,并且不了解第二个while
的来源。这是一个优先问题。
此代码只是为了表明可以完成。有关应该的完成方式,请参阅Stefan的answer:
end
输出:
array = (1..1000).to_a
while (array.reject! do |element|
rand < 0.5
end)
p array.size
end
答案 3 :(得分:1)
在我需要调用方法直到返回值是我想要的情况下,我的个人偏好是:
:keep_going while my_method
或者更简洁地说,我有时会使用:
:go while my_method
它是一行,您可以使用符号的内容来帮助记录正在进行的操作。有了你的阻止,我个人会创建一个proc / lambda并将其传递给拒绝以便清楚。
# Harder to follow, IMHO
:keep_going while array.reject! do |...|
more_code
end
# Easier to follow, IMHO
simplify = ->(...){ ... }
:keep_simplifying while array.reject!(&simplify)