Ruby中Pry异常行为探究:局部变量与方法优先级疑问
Ruby中Pry绑定的变量查找逻辑:局部变量为何优先于同名方法?
问题背景
以下代码中,Animal类通过attr_accessor定义了name的getter/setter方法,实例fish的name属性值为"Nemo"。但在change_name方法里,插入binding.pry后,在Pry控制台输入name得到的是nil,而非预期的"Nemo";同时方法内的p name也不会报错“未定义局部变量”。
class Animal attr_accessor :name def initialize(name) @name = name end def change_name binding.pry p name name = name.upcase end end fish = Animal.new('Nemo') p fish.name # => 'Nemo' p fish.change_name
解答
1. Pry确实优先查找方法内的局部变量
Ruby的变量查找遵循词法作用域规则:在方法内部,Ruby会优先查找当前作用域内的局部变量,只有当局部变量不存在时,才会向上查找方法、常量或全局变量。
具体到这个例子,虽然name = name.upcase这行代码在binding.pry之后,但Ruby在解析方法体时,会扫描整个方法的代码,一旦发现有对name的赋值操作,就会提前在当前方法的作用域中声明这个局部变量(初始值为nil)。所以当你在Pry中输入name时,找到的是这个已经声明但尚未赋值的局部变量,而非类的name getter方法。
2. 第9行p name不报错的原因
这同样是Ruby的变量提升特性导致的:只要方法体中存在对某个变量的赋值操作(无论代码执行顺序的先后),Ruby在解析阶段就会把该变量标记为当前方法的局部变量。因此执行p name时,它访问的是已经被声明(只是还没赋值)的局部变量name,值为nil,而非调用name方法,所以不会触发“未定义局部变量”的错误。
如果想要在方法内明确调用name getter方法,需要显式使用self.name:
def change_name binding.pry p self.name # 输出"Nemo" self.name = self.name.upcase end
内容的提问来源于stack exchange,提问作者SrdjaNo1
相关产品推荐
相关产品推荐

