4

设备型号具有以下属性:名称、版本和全名

全称是名称+版本:

class Device < ActiveRecord::Base
  def prepare
    full_name = (!show_version || version.nil?)? name : name + " " + version.to_s
  end
end

当我执行以下操作时:

d = Device.new :name => "iPhone", :version => "4"
d.prepare
d.full_name # get nil

“full_name”属性我得到 nil

当我使用“自我”时,它可以工作:

class Device < ActiveRecord::Base
  def prepare
    self.full_name = (!show_version || version.nil?)? name : name + " " + version.to_s
  end
end

做“准备”我得到“全名”属性的“iPhone 4”。

这里的一些人告诉我,避免在类方法中使用“self”是一种很好的方式。但这带来了麻烦。

问题是 - 为什么不使用 "self" 就不能工作?

4

3 回答 3

14

在这些情况下,你必须使用 self,我不认为这很麻烦。如果您正在使用,self那么解释器将知道您引用了对象的属性。如果你不使用self它意味着它只是一个局部变量,在方法完成后不会存储在任何地方。这是正常行为。您也可以self[:full_name]= ...用作 setter 方法,但在这种情况下并不重要。

更新

@AntonAL

因为 getter 方法在没有self..

当您尝试使用该name属性时,解释器将在当前方法中查找局部变量。如果没有找到,则查找实例属性。例子:

def your_method
  self.name = 'iPhone'
  puts name
  #iPhone
  name = 'iPod'
  puts name
  #iPod
  puts self.name
  #iPhone
end

并将iPhone存储在您的对象实例的name属性中。并且iPod在方法完成后会丢失。

于 2011-03-20T15:30:26.737 回答
13

当您使用 setter 时,您需要使用self,否则 Ruby 会将其解释为full_name正在定义的新局部变量。

对于getter,我们不需要调用self,因为Ruby首先搜索局部变量full_name,当它没有局部变量时full_name,它会搜索方法full_name并获取getter。如果定义了局部变量full_name,它将返回局部变量的值。

这在上一个问题中得到了更好的解释

于 2011-03-20T15:46:11.460 回答
0

这是意料之中的,因为它是 ActiveRecord 的设计工作方式。如果需要设置任意属性,则必须使用不同类型的对象。

例如,Ruby 提供了一个名为

开放结构

这允许您创建可以分配任意键和值的对象。如果您想从不带 self 的属性中获取值,它将为您提供具有实例全局变量属性的类 OpenStruct 的实例。但是如果你想设置新属性,它会创建具有新属性的类 OpenStruct 的新实例。没有 self 你将拥有旧的 OpenStruct 对象,它没有属性并且会给你错误。

您可能希望使用此类库,然后仅在需要保存到数据库时将对象转换为相应的 ActiveRecord 实例。

不要尝试将 ActiveRecord 建模为您刚才描述的行为,因为它根本不是为了以这种方式行为而设计的

于 2018-11-06T10:27:30.850 回答