Почему я не могу использовать фигурные скобки с циклом `for` в Ruby? - PullRequest
0 голосов
/ 12 мая 2019

В документации Ruby говорится, что "do/end эквивалентно фигурным скобкам", поэтому почему при попытке выполнить следующее я не получаю никакого вывода:

a = [1, 2, 3]
for i in a {
  puts i
}

Когда я выполняю вышеописанное, я не получаю вывод (но я также не получаю сообщение об ошибке).Однако, когда я делаю следующее, все происходит так, как должно быть:

a = [1, 2, 3]
for i in a do
  puts i
end
#=> 1
#=> 2 
#=> 3

Я знаю, что это можно сделать более идиоматически с помощью оператора each, но я не об этом.Что я здесь не понимаю?

Ответы [ 2 ]

3 голосов
/ 12 мая 2019

В документации 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):

  1. разделитель выражений . Разделитель выражений может быть либо

    1. точка с запятой ;
    2. перевод строки
  2. Ключевое слово 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
0 голосов
/ 12 мая 2019

Посмотрите документацию здесь: Для цикла В нем говорится:

Как и в то время, пока, do не является обязательным.Цикл for аналогичен использованию каждого, , но не создает новую переменную scope .

А также

Цикл for используется редков современных программах ruby.

Итак, будьте менее Pythonic :), используя Enumerator # каждый вместо:

a.each { |a| puts a }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...