实例变量:self vs @

时间:2009-11-07 14:37:12

标签: ruby self instance-variables

以下是一些代码:

class Person
  def initialize(age)
    @age = age
  end

  def age
    @age
  end

  def age_difference_with(other_person)
    (self.age - other_person.age).abs
  end

  protected :age
end

我想知道的是@age方法中使用self.ageage_difference_with之间的区别。

6 个答案:

答案 0 :(得分:252)

@age直接访问实例变量@age。编写self.age告诉对象自己发送消息age,它通常会返回实例变量@age - 但可以执行任何其他操作,具体取决于age的方式方法在给定的子类中实现。例如,您可能有一个MiddleAgedSocialite类,它总是报告其年龄比实际年龄小10岁。或者更实际上,PersistentPerson类可能会懒惰地从持久性存储中读取该数据,并将其所有持久性数据缓存在散列中。

答案 1 :(得分:23)

不同之处在于它正在将该方法的使用与其实现隔离开来。如果财产的实施要改变 - 比如保持生日,然后根据现在和生日之间的时间差计算年龄 - 那么取决于方法的代码不需要改变。如果它直接使用该属性,那么更改将需要传播到代码的其他区域。从这个意义上讲,直接使用属性比使用类提供的接口更脆弱。

答案 2 :(得分:5)

Struct.new继承一个类,这是一种生成初个化程序的简洁方法(How to generate initializer in Ruby?)时会收到警告

class Node < Struct.new(:value)
    def initialize(value)
        @value = value
    end
    def show()
        p @value
        p self.value # or `p value`
    end
end 

n = Node.new(30)
n.show()

将返回

30
nil

但是,当您删除初始化程序时,它将返回

nil
30

使用类定义

class Node2
    attr_accessor :value
    def initialize(value)
        @value = value
    end
    def show()
        p @value
        p self.value
    end
end

您应该提供构造函数。

n2 = Node2.new(30)
n2.show()

将返回

30
30

答案 3 :(得分:2)

没有任何区别。我怀疑这只是为了看到self.ageother_person.age彼此靠近的纪录片价值。

我认为使用确实允许在将来编写实际的getter,这可能比返回实例变量更复杂,在这种情况下该方法不需要更改。

但是,这是一个不太可能的担忧,毕竟,如果对象的实现改变了改变其他方法的合理性,那么在某个方面,对象本身内的简单引用是完全合理的。

在任何情况下,age属性的抽象仍然无法解释self的显式使用,因为普通age也会调用访问者。

答案 4 :(得分:1)

第一个答案是完全正确的,但作为一个相对新手,它并没有立即告诉我它暗示了什么(向自己发送信息?嗯......)。我认为一个简短的例子会有所帮助:

class CrazyAccessors
  def bar=(val)
    @bar = val - 20 # sets @bar to (input - 20)
  end
  def bar
    @bar
  end

  def baz=(value)
    self.bar = value # goes through `bar=` method, so @bar = (50 - 20)
  end

  def quux=(value)
    @bar = value     # sets @bar directly to 50
  end
end

obj  = CrazyAccessors.new
obj.baz = 50
obj.bar  # => 30
obj.quux = 50
obj.bar  # => 50

答案 5 :(得分:-2)

@age - 绝对是实例变量年龄

self.age - 指实例属性年龄。