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
' eigenclass。所以def a
创建了一个a
在Foo
eigenclass 中调用的新方法,可以通过正常的方法调用语法访问: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
类上定义的,而是在 的 eigenclass 上定义的str
,它是 的唯一匿名子类String
。所以str
有一种frob
方法,但String
一般情况下没有。我们还可以覆盖 String 的方法(在某些棘手的测试场景中非常有用)。
现在我们有能力理解您的原始示例。Inside的Foo
initialize 方法,self
不是指类Foo
,而是指Foo
. 它的 eigenclass 是 的子类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.
希望这可以帮助。