I have a question regarding the and/&&/= keywords in Ruby.
The ruby docs say that the precedence for the mentioned keywords is: (1)&&, (2)=, (3)and.
I have this snippet of code I wrote:
def f(n)
n
end
if a = f(2) and b = f(4) then
puts "1) #{a} #{b}"
end
if a = f(2) && b = f(4) then
puts "2) #{a} #{b}"
end
The output is:
1) 2 4 [Expected]
2) 4 4 [Why?]
For some reason using the && causes both a and b to evaluate to 4?
I don't quite understand the question you are asking. I mean, you have already given the answer yourself, before even asking the question: &&
binds tighter than =
while and
binds less tightly than =
.
So, in the first case, the expression is evaluated as follows:
( a=f(2) ) and ( b=f(4) )
( a= 2 ) and ( b=f(4) )
2 and ( b=f(4) ) # a=2
2 and ( b= 4 ) # a=2
2 and 4 # a=2; b=4
4 # a=2; b=4
In the second case, the evaluation is as follows:
a = ( f(2) && ( b=f(4) ) )
a = ( 2 && ( b=f(4) ) )
a = ( 2 && ( b= 4 ) )
a = ( 2 && 4 ) # b=4
a = 4 # b=4
4 # b=4; a=4
The reason is simple: precedence. As you say, the order is:
- &&
- =
- and
Since &&
has precedence over =
, the statement is evaluated like this:
if a = (f(2) && (b = f(4))) then
Which results in:
if a = (2 && 4) then
When x
and y
are integers, x && y
returns y
. Thus 2 && 4
results in a = 4
.
For comparison's sake, the first one is evaluated like this:
if (a = f(2)) and (b = f(4)) then
From Programming Ruby 1.9:
The only difference in the two forms is precedence (
and
binds lower than&&
).
I do not know the specific rules that can help in this situation, but let's use the priorities of operations. Using the rules of priorities, we can divide the computation of the second expression on several steps
1 f(2) && b => expr1
2 expr1 = f(4) => expr2
3 a = expr2
Obvious that in Step 2 we get an incorrect situation - on the left side of = is rvalue - temporary object, which can not be assigning by any value. I assume that syntactic analyzer break the rules of priority evaluation of expressions when encounter such situations. More details on the calculations of expressions can be found here
if you modify your code like this you will get what you expect
def f(n)
n
end
if (a = f(2) and b = f(4)) then
puts "1) #{a} #{b}"
end
if (a = f(2) and b = f(4)) then
puts "2) #{a} #{b}"
end
1) 2 4
2) 2 4
精彩评论