类定义/范围中的局部变量

时间:2012-05-04 16:20:37

标签: ruby scope

我的印象是Ruby中的类定义可以重新打开:

class C
  def x
    puts 'x'
  end
end

class C
  def y
    puts 'y'
  end
end

这按预期工作,y被添加到原始类定义中。

我很困惑为什么以下代码无法正常工作:

class D
  x = 12
end

class D
  puts x
end

这将导致NameError例外。为什么在重新打开课程时会启动新的本地范围?这似乎有点违反直觉。在扩展类时,有没有办法继续以前的本地范围?

4 个答案:

答案 0 :(得分:8)

本地变量与对象无关,它们与范围相关联。

局部变量是词法范围的。你要做的事情不再有效:

def foo
  x = :hack if false  # Ensure that x is a local variable
  p x if $set         # Won't be called the first time through
  $set = x = 42       # Set the local variable and a global flag
  p :done
end

foo                   #=> :done 

foo                   #=> nil (x does not have the value from before)
                      #=> done

在上面,它是同一个对象的同一个方法,它被执行两次。 self没有变化。但是,在调用之间清除局部变量。

重新打开该类就像再次调用一个方法:您处于相同的self范围内,但是您正在启动一个新的本地上下文。当您使用class D关闭end块时,您的本地变量将被丢弃(除非它们是closed over)。

答案 1 :(得分:6)

在ruby中,局部变量只能在定义它们的范围内访问。但是,class关键字会导致全新的范围。

class D
  # One scope
  x = 12
end

class D
  # Another scope
  puts x
end

因此,您无法访问第一个class部分中定义的局部变量,因为当您离开第一个范围时,其中的局部变量将被销毁,内存将被垃圾收集释放。

例如,def也是如此。

答案 2 :(得分:0)

简单的解决方案是将 x 设为class instance variable。当然,这不能回答你的范围问题。我认为 x 不在重新打开的类的scope(参见检测Ruby变量的范围)的原因是因为它的范围从未首先是 D 类的。 x 的范围在类 D 关闭时结束,因为 x 既不是实例变量也不是类变量。

我希望有所帮助。

答案 3 :(得分:0)

这种行为有意义的部分原因在于元编程功能;您可以使用一些临时变量来存储可用于命名新常量的数据,或引用方法名称:

class A
  names, values = get_some_names_and_values()

  names.each_with_index do |name, idx|
    const_set name, value[idx]
  end
end

或许,你需要获得本征类......

class B
  eigenclass = class << self; self; end
  eigenclass.class_eval do
    ...
  end
end

每次重新打开一个类都有一个新的作用域是有道理的,因为在Ruby中你经常在一个类定义中编写代码,这个代码是要执行的实际代码,而打开类只是一个为self获得正确价值的方法。您不希望这些变量污染类的内容,否则您将使用类实例变量:

class C
    @answer = 42
end

class C
  p @answer
end