Почему в Ruby вызов метода не может рассматриваться как единое целое при использовании «do» и «end»? - PullRequest
9 голосов
/ 04 мая 2010

Следующий вопрос относится к вопросу " Ruby Print Inject Do Syntax ". Мой вопрос: можем ли мы настаивать на использовании do и end и заставить его работать с puts или p?

Это работает:

a = [1,2,3,4]

b = a.inject do |sum, x|
  sum + x
end
puts b   # prints out 10

Итак, правильно ли сказать, inject - это метод экземпляра объекта Array, и этот метод экземпляра принимает блок кода, а затем возвращает число. Если это так, то это не должно отличаться от вызова функции или метода и возврата возвращаемого значения:

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, можно ли заставить его работать?

Ответы [ 2 ]

15 голосов
/ 04 мая 2010

Из (неофициальной) ruby ​​грамматики мы видим, что содержание (...) в puts (...) должно быть CALL_ARGS, которое не уменьшается непосредственно до STMT. Однако их можно уменьшить до '(' COMPSTMT ')'. Включая дополнительный набор скобок, вы можете использовать do ... end.

a = [1,2,3,4]

puts ((a.inject do |sum, x| 
         sum + x   
       end))
7 голосов
/ 04 мая 2010

Проблема здесь не только в ваших скобках: это прежде всего пробел после puts перед скобками.

С кодом

a = [1,2,3,4]

puts (a.inject do |sum, x|
             sum + x
                    end)

Мы получаем синтаксические ошибки, перечисленные в вопросе.

Если вы оставите пробел после puts,

a = [1,2,3,4]

puts(a.inject do |sum, x|
             sum + x
                    end)

распечатывает 10 как положено.

Наконец, использование puts ((a.inject... с пробелом и двойными круглыми скобками также выводит 10, но, пропуская через ruby -cw XXX.rb, говорит нам:

a.rb:5: warning: (...) interpreted as grouped expression

Syntax 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.map do foo end эквивалентно (p a.map) do foo end, что, конечно, не принимает аргумент блока.

См. Также краткий справочник Ruby по блокам (особенно последние две строки):

Блоки, затворы и процы

Блоки / Затворы

  • блоки должны следовать за вызовом метода:

invocation do ... end

invocation { ... }

  • Блоки помнят свой переменный контекст и являются полными замыканиями.
  • Блоки вызываются через yield и могут передаваться аргументы.
  • Форма фигурной скобки имеет более высокий приоритет и будет привязана к последнему параметру, если вызов сделан без паренов.
  • форма do / end имеет более низкий приоритет и будет привязана к вызову даже без символов.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...