Ruby大括号与do-end方法链接

时间:2013-12-06 13:11:51

标签: ruby method-chaining

我找到了一个问题:Nested Loops Ruby并解决了它,但解决方案看起来很难看(虽然有效):

puts (1..10).map { |i| (i..10).step(i).inject(0) { |memo, obj| memo = memo | 2**(obj-1) } }.inject(0) { |memo, obj| memo = memo ^ obj}

重写为多行,但保持花括号:

puts (1..10).map { |i| 
    (i..10).step(i).inject(0) { |memo, obj| 
        memo = memo | 2**(obj-1)
        }
    }.inject { |memo, obj|
        memo = memo ^ obj
        }

我尝试将其重写为多行do-end块以使其更具可读性(了解{}do-end之间的优先级差异)但是我收到错误(我刚刚更改了最后一个)括号):

puts (1..10).map { |i| 
    (i..10).step(i).inject(0) { |memo, obj| 
        memo = memo | 2**(obj-1)
        }
    }.inject do |memo, obj|
        memo = memo ^ obj
        end.to_s(2)
../../bitflipping.rb:5:in 'each': no block given (LocalJumpError)
    from ../../bitflipping.rb:5:in 'inject'
    from ../../bitflipping.rb:5:in ''

是否可以使用do-end重写此内容?我认为存在一个优先级问题,我如何重新组合它们,例如inject在最后得到正确的块?

2 个答案:

答案 0 :(得分:0)

尝试将它变成一种方法,也许吧?虽然sawa说,map{|x| x}没有做任何事情

def my_method 
  first_step = (1..10).map do |i| 
    (i..10).step(i).map { |x| x}.inject(0) { |memo, obj| memo = memo | 2**(obj-1) }
  end
  second_step = first_step.inject { |memo, obj| memo = memo ^ obj}.to_s(2)
  return second_step
end

puts my_method

答案 1 :(得分:0)

触发问题的句法结构是没有括号的puts

您可以通过重构代码来解决问题,以便首先将结果分配给变量(例如result),然后再执行puts result

替代解决方案是将整个表达式包装在括号中。

这里是对场景的精简再现:

# OK, because assignment has lower precedence than do/end 
result = (1..10).inject do |memo, obj|
  memo + obj
end
puts result

# OK because the outer parentheses resolves the ambiguity
puts(
  (1..10).inject do |memo, obj|
    memo + obj
  end
)

# ERROR: no block given
puts (1..10).inject do |memo, obj|
  memo + obj
end

发生错误是因为do / end块的优先级低于方法调用(没有括号)。

ERROR案例相当于:

puts( (1..10).inject ) do |memo, obj|
  memo + obj
end

...换句话说,您将该块传递给puts而不是inject。并且inject(至少在这种情况下)失败,因为它需要一个块。