В Ruby, почему вызов метода не в состоянии рассматриваться как единицу, когда "делают" и используется “конец”?

Следующий вопрос связан с вопросом "Печать 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, это может быть сделано работать?

9
задан Community 23 May 2017 в 11:43
поделиться

2 ответа

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

a = [1,2,3,4]

puts ((a.inject do |sum, x| 
         sum + x   
       end))
15
ответ дан 4 December 2019 в 09:35
поделиться

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

С кодом

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 имеет более низкий приоритет и будет привязываться к вызову даже без скобок.
7
ответ дан 4 December 2019 в 09:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: