我错过了某个地方的备忘录,我希望你能向我解释这个。
为什么对象的本征类与self.class
不同?
class Foo
def initialize(symbol)
eigenclass = class << self
self
end
eigenclass.class_eval do
attr_accessor symbol
end
end
end
将特征类与class.self
等同起来的逻辑逻辑非常简单:
class << self
是一种声明类方法的方法,而不是实例方法。这是def Foo.bar
的捷径。
因此,在对类引用的引用中,返回self
应该与self.class
相同。这是因为class << self
会将self
设置为Foo.class
以定义类方法/属性。
我只是困惑吗?或者,这是Ruby元编程的一个偷偷摸摸的技巧吗?
答案 0 :(得分:120)
class << self
不仅仅是一种声明类方法的方法(尽管可以这样使用)。可能你已经看到了一些用法:
class Foo
class << self
def a
print "I could also have been defined as def Foo.a."
end
end
end
这有效,相当于def Foo.a
,但它的工作方式有点微妙。秘诀是self
在该上下文中引用了对象Foo
,其类是Class
的唯一匿名子类。该子类称为Foo
的本征类。因此,def a
在a
的本征类中创建了一个名为Foo
的新方法,可通过常规方法调用语法访问:Foo.a
。
现在让我们看一个不同的例子:
str = "abc"
other_str = "def"
class << str
def frob
return self + "d"
end
end
print str.frob # => "abcd"
print other_str.frob # => raises an exception, 'frob' is not defined on other_str
此示例与最后一个示例相同,但最初可能很难说。 frob
的定义不是String
类,而是str
的本征类,String
的唯一匿名子类。因此,str
具有frob
方法,但String
的实例通常不会。我们也可以覆盖String的方法(在某些棘手的测试场景中非常有用)。
现在我们已经准备好了解您的原始示例。在Foo
的初始化方法中,self
不是指Foo
类,而是指Foo
的某个特定实例。它的本征类是Foo
的子类,但它不是Foo
;它不可能,否则我们在第二个例子中看到的技巧无法奏效。所以继续你的例子:
f1 = Foo.new(:weasels)
f2 = Foo.new(:monkeys)
f1.weasels = 4 # Fine
f2.monkeys = 5 # Also ok
print(f1.monkeys) # Doesn't work, f1 doesn't have a 'monkeys' method.
希望这有帮助。
答案 1 :(得分:45)
最简单的答案:无法实例化本征类。
class F
def eigen
class << self
self
end
end
end
F.new.eigen.new #=> TypeError: can't create instance of virtual class
答案 2 :(得分:11)
Yehuda Katz在解释“Metaprogramming in Ruby: It's All About the Self”中的微妙之处方面做得非常出色