为什么在 Ruby/Rails/ActiveRecord 中并不总是需要使用 self?

50

在测试Rails模型中的getter/setter对时,我发现了一个好的例子,它展示了我一直认为很奇怪和不一致的行为。

在这个例子中,我正在处理 class Folder < ActiveRecord::Base

Folder belongs_to :parent, :class_name => 'Folder'

在getter方法中,如果我使用:

def parent_name
  parent.name
end

...or...

def parent_name
  self.parent.name
end

...结果完全一样,我获得了父文件夹的名称。但是,在getter方法中,如果我使用...

def parent_name=(name)
  parent = self.class.find_by_name(name)
end

...当parent变为nil时,但如果我使用...

def parent_name=(name)
  self.parent = self.class.find_by_name(name)
end

......然后它就能工作了。

所以,我的问题是,为什么有时需要声明self.method,而不能只使用局部变量呢?

看起来,在ActiveRecord中需要/使用self是不一致的,我想更好地理解这一点,这样我就不会总是猜测是否需要声明self。在ActiveRecord模型中什么情况下应该/不应该使用self?


3
为什么 Ruby 中的 Setter 需要在类内使用 self. 限定符?调用类属性访问器方法时如何处理?什么时候应该在 Ruby 中使用 self?为什么在没有使用 self 的情况下调用本地方法会产生不同的行为?在 Ruby 中,什么时候应该在类中使用 self.?如果我们定义了一个名为 c= 的方法,为什么不能通过 c = 3 调用它? - Jörg W Mittag
也可以在这里找到重复的内容(https://dev59.com/fmw15IYBdhLWcg3wWqZ0#6671310),其中“我曾经是学习者,现在我是大师”;) - Andrew
1个回答

89

这是因为属性/关联实际上是方法(获取器/设置器)而不是局部变量。当你声明“parent = value”时,Ruby假设你想将值分配给局部变量parent。

在堆栈的某个位置有一个设置器方法“def parent =”,要调用它,必须使用“self.parent =”告诉Ruby你实际上想调用一个设置器而不仅仅是设置一个局部变量。

对于获取器,Ruby首先查找是否存在局部变量,如果找不到,则尝试查找同名的方法,这就是为什么你的获取器方法可以在没有“self”的情况下工作的原因。

换句话说,这不是Rails的错,而是Ruby固有的工作方式。


5
哇,太完美了。它作为getter工作是因为Ruby没有找到本地变量,因此查找方法。换句话说,如果我想表示self,我应该使用self,而不是省略它。哇,这是一个非常非常非常有帮助的解释。 - Andrew
确实,感谢您的解释(以及写得很好的问题)。 - Fábio Batista
这篇回答关于ActiveRecord模型方法的动态性质的解释使得这一点更加清晰。Ruby理解类层次结构,但不一定理解那些通过method_missing动态生成或处理的方法。 - jxpx777
非常好的解释!救了我的命。虽然现在还感觉有点混淆,但我认为我已经掌握了一个非常重要的概念,作为一个慢学习者,我相信我很快就能理解你的完整解释,再次感谢这个精彩的解释! - Jesse JunJing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接