В документации Ruby говорится, что "do/end
эквивалентно фигурным скобкам"
Нет, это не так. Это говорит ( жирный шрифт выделено мной):
В этом контексте , do
/ end
эквивалентно фигурным скобкам […]
Что означает «в этом контексте», определяется непосредственно перед цитируемым вами половинным предложением:
do
В паре с end
, может разделять кодовый блок
Итак, «в этом контексте» здесь относится к контексту блока .
так почему, когда я пытаюсь сделать следующее, я не получаю никакого вывода
Поскольку это совершенно другой контекст, снова приведу цитаты из документации, на которую вы ссылались:
do
может также (опционально) появляется в конце оператора for
/ in
. (См. for
для примера.)
«также» в этом предложении очень ясно показывает, что это другое использование ключевого слова do
, которое не имеет ничего общего с использованием, обсужденным в этом разделе. И если вы посмотрите на документацию for
, вы увидите, что нет никаких упоминаний о разрешенных фигурных скобках.
Когда я выполняю вышеизложенное, я не получаю вывод (но я также не получаю сообщение об ошибке).
Это не правда. Ваш код синтаксически неверен, потому что в нем отсутствует ключевое слово end
для завершения выражения for
/ in
, поэтому в строке 4 появляется «синтаксическая ошибка, неожиданный конец ввода»:
ruby -c -e 'a = [1, 2, 3]
for i in a {
puts i
}'
# -e:4: syntax error, unexpected end-of-input
И если вы добавите недостающий end
, вы получите in `<main>': undefined method `a' for main:Object (NoMethodError)
в строке 2:
ruby -e 'a = [1, 2, 3]
for i in a {
puts i
}
end'
# -e:2:in `<main>': undefined method `a' for main:Object (NoMethodError)
Опять же, это ожидается, потому что фигурные скобки ограничивают блок кода, поэтому
a {
puts i
}
интерпретируется как блок кода, передаваемый в a
, и поскольку переменные не могут принимать аргументы, только методы могут, a
должен быть методом. Поэтому Ruby по праву жалуется на отсутствие метода с именем a
.
Существует три способа отделения выражения итератора от выражения тела цикла в цикле for
/ in
(на самом деле то же самое относится к циклам while
и until
):
разделитель выражений . Разделитель выражений может быть либо
- точка с запятой
;
- перевод строки
Ключевое слово do
Итак, все следующие исправления будут для вашего кода:
# non-idiomatic
for i in a; puts i end
# non-idiomatic
for i in a
puts i end
# the same but with idiomatic indentation and whitespace
for i in a
puts i
end
# idiomatic
for i in a do puts i end
# redundant, non-idiomatic
for i in a do
puts i
end
Обратите внимание, что когда я говорю "идиоматический" выше, это следует интерпретировать относительно, поскольку на самом деле for
/ in
циклы в целом полностью не идиоматичны, и вы бы предпочли сделать это:
a.each do |i|
puts i
end
или, может быть
a.each(&method(:puts))
Как правило, предпочтительнее не смешивать ввод-вывод и преобразование данных, поэтому другим идиоматическим решением было бы сначала преобразовать данные в желаемый вывод, а затем вывести его, например:
puts a.join("\n")
За исключением того, что Kernel#puts
уже будет обрабатывать Array
аргументов специальными и печатать каждый элемент в отдельной строке (как описано в IO#puts
), поэтому реальное правильное идиоматическое решение для вашего кода будет просто:
puts a