Ответ 1
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
, а на собственном элементе str
, уникальном анонимном подклассе String
. Итак, str
имеет метод frob
, но экземпляры String
вообще не делают. Мы могли бы также переопределить методы String (очень полезно в некоторых сложных сценариях тестирования).
Теперь мы готовы понять ваш оригинальный пример. Внутри метода 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.
Надеюсь, что это поможет.