Ruby on Rails - Ruby Operator Precedence - Parentheses

杀马特。学长 韩版系。学妹 提交于 2019-12-22 20:13:10

问题


The following code results in an error

Example 1

if params[:id] == '2' || params.has_key? :id
  abort('params id = 2 or nothing')
end


syntax error, unexpected tSYMBEG, expecting keyword_then or ';' or '\n'
if params[:id] == '2' || params.has_key? :id

However, switching the conditional statements || adding parentheses works 100%.

Example 2

if params.has_key? :id || params[:id] == '2' 
  abort('params id = 2 or nothing')
end

Example 3

if (params[:id] == '2') || (params.has_key? :id)
  abort('params id = 2 or nothing')
end

Can anyone explain to me why Example 1 will result in an error ?

Thanks


回答1:


Your problem is happening at:

params[:id] == '2' || params.has_key? :id

which can be simplified to:

:foo || some_method :bar

which causes the same error. This expression is in principle, ambiguous between

(:foo || some_method) :bar         (1)

and

:foo || (some_method :bar)         (2)

When an expression is ambiguous, it is resolved by other factors. One factor, operator precedence tells nothing here about disambiguating between (1) and (2). The next factor is linear order. Since || appears before argument application () (omitted) in the expression in question, the former applies before the latter. Therefore, the expression is interpreted as (1). Since (:foo || some_method) would then be parsed as an expression, there would be two expressions next to each other. That is ungrammatical, just as:

:baz :bar

is ungrammatical.

In fact, if you switch the order as:

some_method :bar || :foo

then, it will be interpreted as

(some_method :bar) || :foo

for the same reason, and syntax error will disappear.

Also when you resolve ambiguity by explicitly using parentheses to indicate argument application:

:foo || some_method(:bar)

then there is no ambiguity needed to be resolved, and the syntax error disappears.




回答2:


Your :id is a symbol in Ruby.

a = {'id' => 'a', 'value' => 'value'}

a.has_key? 'id'
=> true

a.has_key? :id
=> false

So you need to change your code:

if params[:id] == '2' or params.has_key? 'id'
  abort('params id = 2 or nothing')
end

Note: If you are going to use this code checking for key before checking for value makes more sense.

Note #2: Tested with :

params = {'id' => 'a', 'value' => 'value'}

if params[:id] == '2' or params.has_key? 'id'
  abort('params id = 2 or nothing')
end

and Ruby 2.0.0

Also check this question for more information about Ruby Symbols.




回答3:


It has to do with how Ruby evaluates that if statement.

Example 1 is like if (params[:id] == '2' || params.has_key?) :id

which resolves in an unexpected symbol error as you can see syntax error, unexpected tSYMBEG.




回答4:


As guy says... the parser doesn't assume that the symbol is a parameter for the has_key? method

You can bypass the error by explicitly coding the parentheses

if params[:id] == '2' || params.has_key?(:id)


来源:https://stackoverflow.com/questions/17720115/ruby-on-rails-ruby-operator-precedence-parentheses

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!