未执行的行(被“ if false”阻止)仍会影响结果

时间:2019-03-05 23:38:57

标签: ruby

我想在ActiveInteraction中使用经典的|| =重新分配(cf Set Ruby variable if it is not already defined),就像在https://github.com/AaronLasseigne/active_interaction/issues/395中一样

但是,通过在ActiveInteraction中测试不同的语法,我偶然发现了一个甚至在Vanilly Ruby中也发生过的更奇特的问题。

未执行的行(由if false阻止)仍然会对其余代码产生重大影响:

class A
  attr_accessor :a

  def run
    (puts defined? a; a) if true
  end

  def run2
    (puts 'change a'; a = 0) if false
    puts defined? a
    a
  end

end

x = A.new
x.run  # "method"; nil
x.run2 # "local-variable"; nil
x.a = 5
x.run # "method"; 5
x.run2 # "local-variable"; nil

任何人都可以解释这是错误还是功能?如果有一个功能:怎么来?看起来很奇怪。

编辑:感谢@Sergio Tulentsev的回答,我设法发现我的问题与Ruby instance method & conditional local variable assignment with same name几乎完全相同,但标题名称的重点不同。

1 个答案:

答案 0 :(得分:3)

  

[这]是错误还是功能?

都不是。这是...特殊性。发生的是,当解析器在代码中看到分配给局部变量的代码时,它将继续进行操作并将名称添加到作用域(从该行开始,可能会覆盖其他名称,例如此处的方法)。默认值为nil。如果实际的赋值从未执行过,则新的局部变量仍在作用域内,并且仍求值为nil

这在https://docs.ruby-lang.org/en/2.5.0/syntax/assignment_rdoc.html#label-Local+Variables+and+Methods中有记录。