Следующий вопрос связан с вопросом "Печать Ruby, Вводят, Делают Синтаксис". Мой вопрос, можем мы настаивать на том, чтобы использовать do
и end
и заставьте его работать с puts
или p
?
Это работает:
a = [1,2,3,4]
b = a.inject do |sum, x|
sum + x
end
puts b # prints out 10
таким образом, это корректный для высказывания, inject
метод экземпляра объекта Массива, и этот метод экземпляра берет блок кода и затем возвращает число. Если так, затем это должно не отличаться от вызывания функции или метода и возвращения возвращаемое значение:
b = foo(3)
puts b
или
b = circle.getRadius()
puts b
В вышеупомянутых двух случаях мы можем непосредственно сказать
puts foo(3)
puts circle.getRadius()
таким образом нет никакого способа заставить его работать непосредственно при помощи следующих 2 путей:
a = [1,2,3,4]
puts a.inject do |sum, x|
sum + x
end
но это дает
ch01q2.rb:7:in `inject': no block given (LocalJumpError)
from ch01q2.rb:4:in `each'
from ch01q2.rb:4:in `inject'
from ch01q2.rb:4
группировка использования вызова метода ( )
не работает также:
a = [1,2,3,4]
puts (a.inject do |sum, x|
sum + x
end)
и это дает:
ch01q3.rb:4: syntax error, unexpected kDO_BLOCK, expecting ')'
puts (a.inject do |sum, x|
^
ch01q3.rb:4: syntax error, unexpected '|', expecting '='
puts (a.inject do |sum, x|
^
ch01q3.rb:6: syntax error, unexpected kEND, expecting $end
end)
^
наконец, следующие работы версии:
a = [1,2,3,4]
puts a.inject { |sum, x|
sum + x
}
но почему не делает группировки использования вызова метода ( )
работа в более раннем примере? Что, если программист настаивает, что использует do
и end
, это может быть сделано работать?
Из (неофициальной) ruby grammar мы видим, что содержимое (...)
в puts (...)
должно быть CALL_ARGS
, которые не сводятся напрямую к STMT
. Однако они могут сводиться к '(' COMPSTMT ')'
. Включив дополнительный набор круглых скобок, можно использовать do ... end
.
a = [1,2,3,4]
puts ((a.inject do |sum, x|
sum + x
end))
Проблема здесь не только в скобках: это прежде всего пробел после помещает
перед скобки.
С кодом
a = [1,2,3,4]
puts (a.inject do |sum, x|
sum + x
end)
мы получаем синтаксические ошибки, которые вы указали в вопросе.
Если вы отбрасываете пробел после того, как помещает
,
a = [1,2,3,4]
puts(a.inject do |sum, x|
sum + x
end)
выводит 10
, как и ожидалось.
Наконец, использование put ((a.inject ...
с пробелом и двойными круглыми скобками также выводит 10
, но пропускает это через ] ruby -cw XXX.rb
сообщает нам:
a.rb: 5: предупреждение: (...) интерпретируется как сгруппированное выражение
Синтаксис OK
ruby -cw
используется для C проверьте синтаксис с включенными полными аргументами W . Когда -cw
включен, вы будете предупреждены о сомнительных скобках и группировке. Ошибка "Я" более привычно видеть, что «не ставьте пробел перед скобками аргументов» - так что не делайте этого тоже!
Наконец, причина a.inject do
не работает без скобок, но a .inject {
работает, заключается в том, что фигурные скобки имеют более высокий приоритет, чем do
/ end
. В качестве очень грубых рекомендаций можно сказать, что p a.map {foo}
эквивалентно p (a.map do foo end)
; и p a.ma p do foo end
эквивалентно (p a.map) do foo end
, который, конечно, не принимает аргумент блока.
См. Также краткий справочник Ruby по блокам (особенно последние две строки):
Blocks, Closures, and Procs
Blocks / Closures
- блоки должны следовать за вызовом метода:
invocation do ... end
invocation {...}
- Блоки запоминают свой переменный контекст и являются полными замыканиями.
- Блоки вызываются через yield и могут быть переданы аргументами.
- Форма скобок имеет более высокий приоритет и привязывается к последнему параметру, если вызов выполняется без скобок.
- Форма do / end имеет более низкий приоритет и будет привязываться к вызову даже без скобок.