Ruby do / end против фигурных скобок

Почему это выражение карты дает разные результаты в зависимости от того, использую ли я фигурные скобки или do / end?

a = [1,2,3,4,5]


p a.map { |n|
    n*2
}  
#=> [2,4,6,8,10]


p a.map do |n|
    n*2
end  
#=> [1,2,3,4,5]

person Grandpa    schedule 01.04.2011    source источник
comment
Это держится до сегодняшнего дня   -  person fotanus    schedule 23.05.2013
comment
Отвечает ли это на ваш вопрос? Использование блока do и фигурных скобок {}   -  person Cees Timmerman    schedule 03.12.2020


Ответы (3)


Это потому, что вторая строка интерпретируется как:

p(a.map) do ... end

вместо:

p(a.map do ... end)

Грамматика в этом случае неоднозначна, и do, похоже, не связывает так сильно, как {.

person DarkDust    schedule 01.04.2011
comment
@Grandpa Это не совсем про букву "p". Речь идет о силе / приоритете между методом, принимающим аргумент / блоки, и {}, действительно конец - person sawa; 01.04.2011
comment
И как можно правильно использовать do...end с многострочным блоком, чтобы map получил его как параметр? Фигурные скобки - как вы предлагаете - этого не сделают, Ruby выдает ошибку, unexpected keyword_do_block даже весь блок представляет собой одну строку. - person karatedog; 08.07.2012
comment
@karatedog: вам, вероятно, придется использовать здесь промежуточную переменную, поскольку синтаксический анализатор не поддерживает то, что вы хотите. - person DarkDust; 09.07.2012
comment
@DarkDust Спасибо, но я не могу использовать промежуточную переменную, когда Enumerator бесконечен, потому что мне нужно заранее знать, сколько элементов я должен сгенерировать в этой промежуточной переменной. - person karatedog; 09.07.2012
comment
Я не понимаю, что вы имеете в виду, конечно, вы можете сделать foo = a.map do ... end ; p(foo). Это точно такая же семантика, потому что map всегда нужно агрегировать массив для передачи в первую очередь. Будет ли этот массив затем сохранен в переменной или передан в качестве параметра другому методу, не имеет значения, массив должен быть создан первым, несмотря ни на что. - person DarkDust; 10.07.2012

Это связано с разницей в ассоциативности символа { и ключевого слова do.

В первом случае блок интерпретируется как аргумент блока для функции map. Результатом функции карты является аргумент функции p.

Во втором случае блок интерпретируется как аргумент блока для функции p, а a.map интерпретируется как первый аргумент функции p. Поскольку a.map оценивается как a, выводится исходный массив. В этом случае блок фактически игнорируется.

person Confusion    schedule 01.04.2011

С синтаксисом do/end вы передаете блок в p в качестве второго аргумента, а не в карту. Вы получите тот же результат с:

p a.map

Блок игнорируется p, поскольку он ничего не производит на inspect.

person Douglas F Shearer    schedule 01.04.2011