单例对象上的attr_accessor未按预期工作

时间:2018-02-28 15:40:58

标签: ruby

为什么Cat.new.name有效,Dog.new.name不起作用,给出这两种不同的实现:

class Cat
end 

Cat.instance_eval do
  attr_accessor :name
end

但这不起作用:

class Dog
  class << self
    attr_accessor :name
  end
end

注意:我知道Dog.name 工作,但我认为这两种实现都会导致创建name name=Dog的所有实例化的Cat方法。

问题背景:

要开始:例如,请使用以下代码:

class Cat
end

Cat.instance_eval do
  attr_accessor :name
end

c = Cat.new
c.name = 'some cat name'
p c.name # => "some cat name"

关于ruby documentation of instance_eval,我将通过以下内容与instance_eval块进行讨论:

  • 我们处于CatCatself)的上下文中,所以从本质上讲,我们正在调用Cat.attr_accessor :name,这是一个说“嘿”的宏,对于从Cat创建的所有实例,为他们提供方法namename=

我正在尝试将这种理解扩展到以下内容,但这是错误的:

class Dog
  class << self
    attr_accessor :name
  end
end

d = Dog.new
d.name = "dog name" # => undefined method `name=' for #<Dog:0x007ff6c3062c20> (NoMethodError)

说实话,我会说class << self说:

  • 将我置于Dog的单例对象的上下文中,因此self现在是Dog的单个对象
  • attr_accessor的单个对象上调用Dog宏(因此我们实际上正在调用<singleton_of_Dog>.attr_accessor :name)。现在每次我们实例化一个Dog对象时,每个狗对象现在都有namename=

错误显然表明我的想法在这里不正确,但我不确定我错过了哪一部分。

我搜索了之前的堆栈溢出问题,阅读了书籍并观看了解释ruby对象模型的视频。尽管如此,显然还有一些我尚未完全掌握的基本概念。

1 个答案:

答案 0 :(得分:1)

class << self的典型用法是创建一个块,其中实例方法被定义为类方法。这使您可以跳过在方法定义中键入self.,并使其他工具可用,如私有/受保护。

如何工作是通过打开Dog的单例类并向其添加实例方法。 Dog's singleton类的实例方法成为Dog的类方法。这只是单例类定义的一部分。

在attr_accessor的情况下,这是你在Dog的类范围内调用的方法,它定义了Dog上的实例方法。

当你在Dog的单例类上调用attr_accessor时,它会在Dog的单例类中创建实例方法。 Dog's singleton类的实例方法成为Dog的类方法。这就是为什么您可以在代码中使用Dog.name =而不是Dog.new.name =的原因。