Рубин пока синтаксис - PullRequest
       0

Рубин пока синтаксис

9 голосов
/ 26 октября 2010

Кто-нибудь, почему я могу написать это:

ruby-1.8.7-p302 > a = %w( a b c)
 => ["a", "b", "c"] 
ruby-1.8.7-p302 > while (i = a.shift) do; puts i ; end
a
b
c
 => nil 

Что похоже на передачу блока в то время как. И не:

while(i = a.shift) { puts i; }

Это потому, что "do" синтаксиса while - это просто синтаксический сахар и ничего общего с "do" блока?

Ответы [ 2 ]

13 голосов
/ 27 октября 2010

Это потому, что do синтаксиса while является просто синтаксическим сахаром и не имеет ничего общего с do блока?

Более или менее, да. Это не синтаксический сахар, это просто встроенная языковая конструкция, такая как def или class, как уже писал @meagar.

Это не имеет ничего общего с do блока, за исключением того, что ключевые слова дороги и поэтому повторное использование ключевых слов имеет смысл. (Под «дорогим» я подразумеваю, что они ограничивают программиста в его выразительности.)

В цикле while есть два способа отделить блок от условия:

  1. ключевое слово do и
  2. разделитель выражений.

В свою очередь, в Ruby есть два разных разделителя выражений:

  1. точка с запятой ; и
  2. перевод строки

Итак, все три из следующих действительны:

while i = a.shift do puts i end # do

while i = a.shift; puts i end   # semicolon

while i = a.shift
  puts i end                    # newline

[Очевидно, что последний не был бы написан таким образом, вы бы поставили end на новой строке, с отступом, чтобы соответствовать while. Я просто хотел продемонстрировать, какой минимум необходим для разделения частей цикла while.]

Между прочим: крайне нелогично ставить условие в скобках. В вашем коде также много лишних точек с запятой. И имя переменной i обычно зарезервировано для индекса, а не для элемента. (Я обычно использую el для родовых элементов, но я предпочитаю больше семантических имен.)

Также очень идиоматично повторять коллекцию вручную. Ваш код был бы намного лучше написан как

a.each(&method(:puts)).clear

Мало того, что гораздо проще понять, что это делает (распечатать все элементы массива и удалить все элементы из него), но и гораздо проще написать (нет способа ошибочно получить условие завершения или винт до любых заданий). Это также оказывается более эффективным: ваша версия & Theta; (n 2 ), эта версия & Theta; (n).

И на самом деле, это не совсем то, как вы бы это написали, потому что Kernel#puts в любом случае уже реализует это поведение. Итак, что бы вы действительно написали бы это

puts a
a.clear

или, может быть, это

a.tap(&method(:puts)).clear

[Примечание: этот самый последний не эквивалентен на 100%. Он печатает новую строку для пустого массива, все остальные ничего не печатают.]

Simple. Очистить. Сжатый. Выразительный. Быстро.

Сравните это с:

while (i = a.shift) do; puts i ; end

Мне на самом деле приходилось запускать это несколько раз, чтобы на 100% понять, что он делает.

7 голосов
/ 26 октября 2010

while не занимает блок, это языковая конструкция.do является необязательным:

while (i = a.shift)
  puts i
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...