为什么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
块:
Cat
(Cat
是self
)的背景下,所以从本质上讲,我们称之为Cat.attr_accessor :name
,这是一个宏,它说“嘿,对于所有从Cat
创建的实例,给他们方法name
和name=
。我试图将这种理解扩展到以下,但它是错误的:
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
is现在Dog
的单身对象attr_accessor
的单个对象上调用Dog
宏(所以我们真的称之为<singleton_of_Dog>.attr_accessor :name
)。现在每次我们实例化一个Dog
对象时,每个狗对象现在都有name
和name=
。错误显然表明我的想法不正确,但我不确定我错过了哪一部分。
我搜索过以前的堆栈溢出问题,阅读书籍和观看解释红宝石对象模型的视频。然而,显然有一些我尚未完全掌握的基本概念。
class << self
的典型用法是创建一个块,其中实例方法被定义为类方法。这使您可以跳过在方法定义中键入self.
,并使其他工具可用,如private / protected。
如何工作是通过打开Dog的单例类并向其添加实例方法。 Dog's singleton类的实例方法成为Dog的类方法。这只是单例类定义的一部分。
在attr_accessor的情况下,这是您在Dog的类范围内调用的方法,它定义了Dog上的实例方法。
当你在Dog的单例类上调用attr_accessor时,它会在Dog的singleton类上创建实例方法。 Dog's singleton类的实例方法成为Dog的类方法。这就是为什么你可以使用Dog.name =
而不是Dog.new.name =
和你的代码。