rails4 AR:本地var在未执行的代码块中声明

时间:2016-02-02 13:46:23

标签: ruby-on-rails ruby-on-rails-4 activerecord

在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。)

谢谢和问候,菲尔

2 个答案:

答案 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.inspectself.name.inspect都调用相同的访问器方法。

下次调用name.inspect时,实际上是调用Ruby解析器初始化为name的局部变量nil

需要注意的是,您应该始终明确使用self。希望这可以帮助。欢呼声。

答案 1 :(得分:1)

这是一个Ruby的东西,而不是Rails的东西。

Ruby没有为if块定义封闭范围。

您可以在此处详细了解原因:https://softwareengineering.stackexchange.com/questions/58900/why-if-statements-do-not-introduce-scope-in-ruby-1-9#answer-60413