这是因为while
语法中的do
只是一种语法糖,与块中的do
没有关系吗?
大体上来说,是的。它不是语法糖,而是内置的语言结构,就像def
或class
一样,正如@meagar已经写过的。
它与块中的do
无关,除了关键字很昂贵,因此重用关键字是有意义的(我所说的“昂贵”是指它们限制了程序员的表达能力)。
在while
循环中,有两种方法将块与条件分开:
do
关键字和
- 表达式分隔符。
而Ruby中有两种不同的表达式分隔符:
- 分号
;
以及
- 换行符。
因此,以下三种方式都是有效的:
while i = a.shift do puts i end
while i = a.shift; puts i end
while i = a.shift
puts i end
[显然,最后一个例子不应该这样写。你应该将
end
放在新的一行,并向左缩进以与
while
匹配。我只是想演示分离
while
循环各部分所需的最少代码。]
顺便说一下,把条件放在括号内是高度不惯用的。你的代码中还有很多多余的分号。而变量名
i
通常用于索引,而非元素。(我通常使用
el
来表示一般的元素,但我更喜欢更语义化的名称。)
手动迭代集合也是十分不惯用的。你的代码可以更好地编写为:
a.each(&method(:puts)).clear
这种写法不仅更易于理解(打印数组的所有元素并删除所有项),而且更容易编写(无法出错终止条件或弄错任何赋值语句)。它还更有效率:您的版本是Θ(n2),而这个版本是Θ(n)。
实际上,那并不是你应该写的方式,因为Kernel#puts
已经实现了这种行为。所以,你真正应该写的是这个:
puts a
a.clear
或者可能是这个
a.tap(&method(:puts)).clear
[注意:最后一个选项并非完全等同。它会为一个空数组打印换行符,而其他所有选项则不会打印任何内容。]
简单。清晰。简洁。表达力强。快速。
与此相比:
while (i = a.shift) do; puts i ; end
我实际上需要运行多次才能完全理解它是做什么的。