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
«s eigenclass . Таким образом def a
создается новый метод с именем a
в собственном Foo
классе, доступный с помощью обычного синтаксиса вызова метода:Foo.a
.
Теперь посмотрим на другой пример:
str = "abc"
other_str = "def"
class << str
def frob
return self + "d"
end
end
print str.frob
print other_str.frob
Этот пример такой же, как и предыдущий, хотя сначала может быть трудно сказать. 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
f2.monkeys = 5
print(f1.monkeys)
Надеюсь это поможет.