未执行的代码覆盖局部变量
Unexecuted code overrides local variable
给出的代码:
class Foo
attr_reader :bar
def initialize
@bar = "abc"
if false
bar = "123"
end
p bar
end
end
Foo.new
结果是
nil
为什么 p bar
在 initialize
中打印 nil
而不是 abc
?
只要行
bar = "123"
被解析,即使不执行,它也会在作用域内将局部变量bar
初始化为nil
。这种行为(局部变量的特征)是由于局部变量采用了词法范围;它们的范围必须在不执行代码的情况下确定。当标记在局部变量和方法之间不明确时,它被解释为局部变量。
试试这个:
class Foo
attr_reader :bar
def initialize
p "instance methods defined in Foo: #{self.methods(false)}"
@bar = "abc"
p "defined? @bar: #{defined? @bar}"
p "bar: #{bar}"
p "defined? bar: #{defined? bar}"
if false
bar = "123"
end
p "defined? bar, 2nd time: #{defined? bar}"
p "bar.nil? = #{bar.nil?}"
p "self.bar = #{self.bar}"
p "instance methods defined in Foo: #{self.class.instance_methods(false)}"
end
end
Foo.new
"instance methods defined in Foo: [:bar]"
"defined? @bar: instance-variable"
"bar: abc"
"defined? bar: method"
"defined? bar, 2nd time: local-variable"
"bar.nil? = true"
"self.bar = abc"
"instance methods defined in Foo: [:bar]"
行数:
"defined? @bar: instance-variable"
"defined? bar: method"
说明@bar
是实例变量,bar
是实例方法,即attr_reader :bar
创建的@bar
的getter方法。之前
if false
bar = "123"
end
被求值,Ruby进入if
子句。她在那里看到 bar = "123"
。如果调用,这会将值 "123"
分配给未初始化的局部变量 bar
.
bar=
不能是实例方法(例如,@bar
的 setter),因为名称以等号结尾的任何方法都必须在 [=81= 上调用]显式接收者。 (它的工作方式允许编码人员使用与实例变量同名的局部变量,减去前导 @
。)
什么是 "explicit" 接收器?如果 Foo
有一个 public 实例方法 buz
,你可以写:
foo = Foo.new
foo.buz
foo
是方法 buz
的显式接收者。要从 Foo
的实例方法之一中调用 buz
,您可以使用显式接收器:
self.buz
或者直接写:
buz
在这种情况下 self
是 隐式 接收者。
因为 bar=
只能用显式接收者来写,我们会写:
attr_writer :bar
...
self.bar = "123"
调用@bar
的setter。
我们在哪里?啊,我们刚刚得出结论:
if false
bar = "123"
end
如果执行了if
子句,会为局部变量bar
赋值,不管是否存在方法Foo#bar=
.
因为false
是,好吧,false
,if
子句的内容没有被执行,所以bar
的值没有从nil
.
重要的是局部变量 bar
和实例变量 @bar
就像 night
和 @day
一样彼此不同。我们可以很容易地证明如下:
a = 'cat'
@a = 'dog'
a #=> "cat"
a = 'pig'
@a #=> "dog"
p bar
不会 return "abc"
因为 bar
和 @bar
是不同的。 @bar
是一个实例变量,但是当你不带前缀@调用它时,ruby搜索局部变量。
一般在ruby,实例变量和全局变量未定义时,returnnil
。但是当 undefined 时局部变量会抛出错误。但是在您的情况下,您已尝试初始化变量,即使由于 if false
而从未初始化它,它仍然已被解析,这足以让 ruby 解释器 return nil
.
中已经解释得很清楚了
给出的代码:
class Foo
attr_reader :bar
def initialize
@bar = "abc"
if false
bar = "123"
end
p bar
end
end
Foo.new
结果是
nil
为什么 p bar
在 initialize
中打印 nil
而不是 abc
?
只要行
bar = "123"
被解析,即使不执行,它也会在作用域内将局部变量bar
初始化为nil
。这种行为(局部变量的特征)是由于局部变量采用了词法范围;它们的范围必须在不执行代码的情况下确定。当标记在局部变量和方法之间不明确时,它被解释为局部变量。
试试这个:
class Foo
attr_reader :bar
def initialize
p "instance methods defined in Foo: #{self.methods(false)}"
@bar = "abc"
p "defined? @bar: #{defined? @bar}"
p "bar: #{bar}"
p "defined? bar: #{defined? bar}"
if false
bar = "123"
end
p "defined? bar, 2nd time: #{defined? bar}"
p "bar.nil? = #{bar.nil?}"
p "self.bar = #{self.bar}"
p "instance methods defined in Foo: #{self.class.instance_methods(false)}"
end
end
Foo.new
"instance methods defined in Foo: [:bar]"
"defined? @bar: instance-variable"
"bar: abc"
"defined? bar: method"
"defined? bar, 2nd time: local-variable"
"bar.nil? = true"
"self.bar = abc"
"instance methods defined in Foo: [:bar]"
行数:
"defined? @bar: instance-variable"
"defined? bar: method"
说明@bar
是实例变量,bar
是实例方法,即attr_reader :bar
创建的@bar
的getter方法。之前
if false
bar = "123"
end
被求值,Ruby进入if
子句。她在那里看到 bar = "123"
。如果调用,这会将值 "123"
分配给未初始化的局部变量 bar
.
bar=
不能是实例方法(例如,@bar
的 setter),因为名称以等号结尾的任何方法都必须在 [=81= 上调用]显式接收者。 (它的工作方式允许编码人员使用与实例变量同名的局部变量,减去前导 @
。)
什么是 "explicit" 接收器?如果 Foo
有一个 public 实例方法 buz
,你可以写:
foo = Foo.new
foo.buz
foo
是方法 buz
的显式接收者。要从 Foo
的实例方法之一中调用 buz
,您可以使用显式接收器:
self.buz
或者直接写:
buz
在这种情况下 self
是 隐式 接收者。
因为 bar=
只能用显式接收者来写,我们会写:
attr_writer :bar
...
self.bar = "123"
调用@bar
的setter。
我们在哪里?啊,我们刚刚得出结论:
if false
bar = "123"
end
如果执行了if
子句,会为局部变量bar
赋值,不管是否存在方法Foo#bar=
.
因为false
是,好吧,false
,if
子句的内容没有被执行,所以bar
的值没有从nil
.
重要的是局部变量 bar
和实例变量 @bar
就像 night
和 @day
一样彼此不同。我们可以很容易地证明如下:
a = 'cat'
@a = 'dog'
a #=> "cat"
a = 'pig'
@a #=> "dog"
p bar
不会 return "abc"
因为 bar
和 @bar
是不同的。 @bar
是一个实例变量,但是当你不带前缀@调用它时,ruby搜索局部变量。
一般在ruby,实例变量和全局变量未定义时,returnnil
。但是当 undefined 时局部变量会抛出错误。但是在您的情况下,您已尝试初始化变量,即使由于 if false
而从未初始化它,它仍然已被解析,这足以让 ruby 解释器 return nil
.