为什么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
现在是Dog
的单个对象attr_accessor
的单个对象上调用Dog
宏(因此我们实际上正在调用<singleton_of_Dog>.attr_accessor :name
)。现在每次我们实例化一个Dog
对象时,每个狗对象现在都有name
和name=
。错误显然表明我的想法在这里不正确,但我不确定我错过了哪一部分。
我搜索了之前的堆栈溢出问题,阅读了书籍并观看了解释ruby对象模型的视频。尽管如此,显然还有一些我尚未完全掌握的基本概念。
答案 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 =
的原因。