Подтвердить что ты не робот

Почему `puts (nil или 4)` терпит неудачу в Ruby?

Когда я это сделаю:

puts(nil or 4)

Ruby жалуется:

SyntaxError: syntax error, unexpected keyword_or, expecting ')'

Почему? puts(nil || 4) работает, но мне интересно, почему or нет. Я думал, что разница между ними была только в их приоритете.

(Я знаю, что выражение nil or 4 не кажется полезным, так как оно всегда возвращает 4. Это просто пример для простоты. Мое фактическое выражение Integer(ENV['WD'] or 4).)

4b9b3361

Ответ 1

Короткий ответ

Потому что это как синтаксис ruby.

Более длинный ответ

and/or ключевые слова были разработаны для использования в конструкциях потока управления. Рассмотрим этот пример:

def die(msg)
  puts "Exited with: #{msg}"
end

def do_something_with(arg)
  puts arg
end

do_something_with 'foo' or die 'unknown error'
# >> foo
# >> Exited with: unknown error

Здесь or работает красиво с рубинными необязательными круглыми скобками, поскольку ruby ​​правила синтаксического анализа (псевдо-BNF).

Короче говоря, список аргументов (CALL_ARGS) - это список ARG, разделенный запятой. Теперь все что угодно - это ARG (определения классов, например, через PRIMARY), но не без исключения EXPR. Если вы окружите выражение круглыми скобками, оно будет соответствовать правилу для "составной инструкции" и, следовательно, будет PRIMARY, что является ARG. Это означает, что

puts( (nil or 4) ) # will work, compound statement as first argument
puts (nil or 4)  # same as above, omitted optional method call parentheses
puts(nil or 4) # will not work, EXPR can't be an argument
puts nil or 4 # will work as `puts(nil) or 4`

Вы можете прочитать грамматику, указанную выше, чтобы точно понять, как она работает.

БОНУС: Пример определения класса является допустимым ARG

puts class Foo
       def bar
         puts "hello"
       end
     end, 'second argument'

# >> bar # this is the "value" of the class definition
# >> second argument

Ответ 2

Это потому, что or и and имеют более низкий приоритет, чем вызов метода. Ваше выражение интерпретируется как:

{puts(nil} or {4)}

где {} обозначает группировку. Синтаксическая ошибка исходит из выражения

puts(nil

(и следующее также приведет к синтаксической ошибке):

4)

Если вы принудительно группируете, поставив пару круглых скобок вокруг выражения, то он будет работать так, как вы планировали:

puts((nil or 4))

Обратите внимание, что внешняя пара скобок используется для вызова метода, а не для группировки, поэтому просто наличие одной пары круглых скобок не влияет на изменение группировки.

В качестве альтернативы, если вы устраните двусмысленность одной пары круглых скобок, которые будут использоваться для группировки путем помещения пробела, то это тоже будет работать:

puts (nil or 4)

Ответ 3

@Сергио Туленцев (и @sawa) дал хороший ответ, но я хочу перефразировать его, чтобы я мог быстро это понять в будущем:

Ruby позволяет нам вырезать круглые скобки в вызовах функций. То есть вместо:

func1(ARG, ARG, ARG) or func2(ARG, ARG, ARG)

Мы можем сделать:

func1 ARG, ARG, ARG or func2 ARG, ARG, ARG

Однако для того, чтобы эта последняя строка вела себя как первая, "или" не может быть оператором, используемым на верхнем уровне ARG (иначе последняя строка будет интерпретироваться как func1(ARG, ARG, ARG or func2 ARG, ARG, ARG)). Действительно, когда мы смотрим в BNF, мы видим, что ARG прямо не упоминает "или" / "и" (что означает, что это незаконно).

Но ARG по-прежнему позволяет использовать "или" : путем обертывания выражения в круглых скобках. В BNF мы рассматриваем это как ПЕРВИЧНУЮ альтернативу, с которой ARG может перейти в (поскольку PRIMARY, в свою очередь, переходит к '(' COMPSTMT ')').

Теперь о том, почему func (1 or 2) и func((1 or 2)) работают, а func(1 or 2) не:

  • func(1 or 2) - это то, что BNF вызывает FUNCTION, которое расширяется до OPERATION ['(' [CALL_ARGS] ')'], что означает, что ARG является "1 или 2", но, как мы видели, ARG не может содержать "или" , поэтому он недействителен.

  • func((1 or 2)), опять же, OPERATION ['(' [CALL_ARGS] ')'], но здесь ARG является "(1 или 2)", что является допустимым ARG (см. вышеприведенный PRIMARY).

  • func (1 or 2) - это то, что BNF вызывает COMMAND, который расширяется до OPERATION CALL_ARGS, что означает, что ARG является "(1 или 2)", что является допустимым ARG (см. вышеприведенный PRIMARY).