ruby attr_accessor 的奇怪行为

Strange behave of ruby attr_accessor

我有这段代码:

class CallMe
  attr_accessor :a, :b, :c

  def self.start(*args)
     self.new(*args).get_answer
  end

  def initialize(a,b,c)
    @a = a
    @b = b
    @c = c
  end

  def get_answer 
    if c
      b = nil
    else
      return b 
    end
   end
end
answer = CallMe.start(1,2,nil)

为什么当我 运行 在 irb 中我总是得到 answer = nil 即使逻辑情况是得到 b 值 2

那是因为在 if 语句的上下文中,您实际上在键入 b = nil 时重新定义了 b。对于 Ruby,不清楚是要调用对象的方法 :b 还是要创建一个新变量 b。在这种情况下,优先级总是从全局到最近的上下文,在这种情况下 - 到 if 块内的上下文。

如果你愿意改变

if c
  b = nil
else
  return b
end

# to 
if c
  # b = nil
  # or
  self.b = nil
else
  return b

您会发现它按预期工作。

可变提升 效果在多种语言中使用。对于 Ruby,它在 official documentation:

中进行了描述

The local variable is created when the parser encounters the assignment, not when the assignment occurs

因此,get_answer 方法创建 local 变量 b 而不管 c 的值。 在创建时将局部变量b赋值给nil。然后 get_answer returns 局部变量 b 总是 nil.

正确方法:

def get_answer
  c ? self.b = nil : b
end