在rails 4.2.5中:是否有可能声明一个locale var,即使它出现在一个未执行的块中? 见这个例子:
class Animal < ActiveRecord::Base
def test
# there is no local var `name`
puts "name " + name.inspect
puts "self.name " + self.name.inspect
if false
name = 'Hund'
end
# now there is a local var `name` (value `nil`)
puts "name " + name.inspect
puts "self.name " + self.name.inspect
end
end
测试它:
>> Animal.new(:name=>'Katze').test
name "Katze"
self.name "Katze"
name nil
self.name "Katze"
我们非常惊讶,name
突然nil
。
出于什么原因,它的行为如下?这是想要的行为吗?因此,我们不能依赖name
,而是将来使用self.name
?
(毫无疑问,应该使用self.name = "Hund"
,但为什么声明了本地var。)
谢谢和问候,菲尔
答案 0 :(得分:4)
重要的是要意识到当你调用self.name
时,你实际上并没有访问变量,而是向访问者方法发送消息
def name
@name
end
了解Ruby解析器如何处理本地变量也很重要,尤其是在条件内部时。这是基础扎实的Rubyist 第6.1.2节
的摘录当Ruby解析器看到序列标识符时,等号,值, 如在这个表达式中
x = 1
它为名为x的局部变量分配空间。创造了 变量 - 不是赋值给它,而是内部赋值 变量的创建 - 总是发生在这种情况下 表达式,即使代码没有执行!考虑这个例子:
if false x = 1 end p x # Output: nil p y # Fatal Error: y is unknown
不会执行对x的赋值,因为它包含在失败中 条件测试。但Ruby解析器看到序列x = 1,来自 它推断该程序涉及局部变量x。该 解析器不关心x是否被赋值。它的工作是 只是为了寻找空间需要的本地变量的代码 被分配。结果是x存在一种奇怪的变量 无人过问。它已经形成并初始化为零。在那里面 尊重,它与一个根本不存在的变量不同;如 你可以在例子中看到,检查x给你的值为nil, 而试图检查不存在的变量y导致a 致命错误。但是虽然x存在,但它并没有起到任何作用 程序。它仅作为解析过程的工件存在。
鉴于上述信息,第一次在代码中调用name.inpspect
时,Ruby解析器知道没有定义这样的局部变量,因此它查看是否存在该名称的方法(它的确如此它由ActiveRecord提供)并调用该方法 - 因此在第一种情况下name.inspect
和self.name.inspect
都调用相同的访问器方法。
下次调用name.inspect
时,实际上是调用Ruby解析器初始化为name
的局部变量nil
。
需要注意的是,您应该始终明确使用self
。希望这可以帮助。欢呼声。
答案 1 :(得分:1)
这是一个Ruby的东西,而不是Rails的东西。
Ruby没有为if
块定义封闭范围。