Класс << self idiom в Ruby
Что делает class << self
в Ruby?
Ответы
Ответ 1
Во-первых, синтаксис class << foo
открывает foo
singleton class (eigenclass). Это позволяет вам специализировать поведение методов, вызываемых этим конкретным объектом.
a = 'foo'
class << a
def inspect
'"bar"'
end
end
a.inspect # => "bar"
a = 'foo' # new object, new singleton class
a.inspect # => "foo"
Теперь, чтобы ответить на вопрос: class << self
открывает класс self
singleton, поэтому методы могут быть переопределены для текущего объекта self
(который внутри тела класса или модуля является самим классом или модулем). Обычно это используется для определения методов класса/модуля ( "статические" ):
class String
class << self
def value_of obj
obj.to_s
end
end
end
String.value_of 42 # => "42"
Это также можно записать в виде сокращения:
class String
def self.value_of obj
obj.to_s
end
end
Или даже короче:
def String.value_of obj
obj.to_s
end
Внутри определения функции self
относится к объекту, с которым вызывается функция. В этом случае class << self
открывает одноэлементный класс для этого объекта; одним из них является внедрение машины с бедным человеком:
class StateMachineExample
def process obj
process_hook obj
end
private
def process_state_1 obj
# ...
class << self
alias process_hook process_state_2
end
end
def process_state_2 obj
# ...
class << self
alias process_hook process_state_1
end
end
# Set up initial state
alias process_hook process_state_1
end
Итак, в приведенном выше примере каждый экземпляр StateMachineExample
имеет process_hook
с псевдонимом process_state_1
, но заметьте, как в последнем он может переопределить process_hook
(только для self
, не влияя на другие StateMachineExample
) до process_state_2
. Таким образом, каждый раз, когда вызывающий абонент вызывает метод process
(который вызывает переопределяемый process_hook
), поведение изменяется в зависимости от того, в каком состоянии оно находится.
Ответ 2
Я нашел супер простое объяснение о class << self
, Eigenclass
и различных типах методов.
В Ruby есть три типа методов, которые могут быть применены к классу:
- Методы экземпляра
- Одиночные методы
- Методы класса
Методы экземпляра и методы класса почти аналогичны их одноименным в других языках программирования.
class Foo
def an_instance_method
puts "I am an instance method"
end
def self.a_class_method
puts "I am a class method"
end
end
foo = Foo.new
def foo.a_singleton_method
puts "I am a singletone method"
end
Другой способ доступа к Eigenclass
(который включает в себя одноэлементные методы) заключается в следующем синтаксисе (class <<
):
foo = Foo.new
class << foo
def a_singleton_method
puts "I am a singleton method"
end
end
теперь вы можете определить одноэлементный метод для self
, который сам является классом Foo
в этом контексте:
class Foo
class << self
def a_singleton_and_class_method
puts "I am a singleton method for self and a class method for Foo"
end
end
end
Ответ 3
Обычно методы экземпляра являются глобальными методами. Это означает, что они доступны во всех экземплярах класса, на котором они были определены. Напротив, однотонный метод реализуется на одном объекте.
Способы хранения Ruby в классах и всех методах должны быть связаны с классом. Объект, на котором определен одноэлементный метод, не является классом (это экземпляр класса). Если только классы могут хранить методы, как объект может хранить одноэлементный метод? Когда создается однопользовательский метод, Ruby автоматически создает анонимный класс для хранения этого метода. Эти анонимные классы называются метаклассами, также известными как одноэлементные классы или eigenclasses. Метод singleton связан с метаклассом, который, в свою очередь, связан с объектом, на котором был определен метод singleton.
Если в одном объекте определены несколько одноэлементных методов, все они хранятся в одном метаклассе.
class Zen
end
z1 = Zen.new
z2 = Zen.new
class << z1
def say_hello
puts "Hello!"
end
end
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
В приведенном выше примере класс < z1 изменяет текущий self, чтобы указать на метакласс объекта z1; то он определяет метод say_hello в метаклассе.
Классы также являются объектами (экземплярами встроенного класса Class). Методы класса - это не что иное, как одиночные методы, связанные с объектом класса.
class Zabuton
class << self
def stuff
puts "Stuffing zabuton…"
end
end
end
Все объекты могут иметь метаклассы. Это означает, что классы также могут иметь метаклассы. В приведенном выше примере класс < self изменяет self, поэтому он указывает на метакласс класса Zabuton. Когда метод определен без явного приемника (класс/объект, на котором будет определяться метод), он неявно определяется в текущей области, то есть текущее значение self. Следовательно, метод stuff определяется в метаклассе класса Zabuton. Вышеприведенный пример - это еще один способ определения метода класса. ИМХО, лучше использовать синтаксис def self.my_new_clas_method для определения методов класса, поскольку он делает код более понятным. Вышеприведенный пример был включен, поэтому мы понимаем, что происходит, когда мы сталкиваемся с классом < self syntax.
Дополнительную информацию можно найти на этот пост о классах Ruby.
Ответ 4
Какой класс < предмет.:
class Hi
self #=> Hi
class << self #same as 'class << Hi'
self #=> #<Class:Hi>
self == Hi.singleton_class #=> true
end
end
[он делает self == thing.singleton_class
в контексте своего блока].
Что такое thing.singleton_class?
hi = String.new
def hi.a
end
hi.class.instance_methods.include? :a #=> false
hi.singleton_class.instance_methods.include? :a #=> true
hi
объект наследует свой #methods
от его #singleton_class.instance_methods
, а затем от #class.instance_methods
.
Здесь мы дали метод экземпляра hi
singleton class :a
. Это можно было бы сделать с помощью class < hi.
hi
#singleton_class
имеет все методы экземпляра hi
#class
имеет и, возможно, еще несколько (:a
здесь).
[методы экземпляра #class
и #singleton_class
могут применяться непосредственно к предмету. когда рубин видит вещь .a, он сначала ищет: определение метода в thing.singleton_class.instance_methods, а затем в thing.class.instance_methods]
Кстати, они вызывают объект singleton class == метакласс == eigenclass.
Ответ 5
А метод singleton - это метод, который определяется только для одного объекта.
Пример:
class SomeClass
class << self
def test
end
end
end
test_obj = SomeClass.new
def test_obj.test_2
end
class << test_obj
def test_3
end
end
puts "Singleton methods of SomeClass"
puts SomeClass.singleton_methods
puts '------------------------------------------'
puts "Singleton methods of test_obj"
puts test_obj.singleton_methods
Одиночные методы SomeClass
тест
Одиночные методы test_obj
test_2
test_3
Ответ 6
Фактически, если вы пишете какие-либо C-расширения для ваших проектов Ruby, существует только один способ определения метода модуля.
rb_define_singleton_method
Я знаю, что этот самостоятельный бизнес просто открывает всевозможные другие вопросы, чтобы вы могли сделать лучше, просматривая каждую часть.
Объекты сначала.
foo = Object.new
Можно ли создать метод для foo?
Конечно,
def foo.hello
'hello'
end
Что мне делать с этим?
foo.hello
==>"hello"
Еще один объект.
foo.methods
Вы получаете все методы Object плюс ваш новый.
def foo.self
self
end
foo.self
Просто объект foo.
Попробуйте посмотреть, что произойдет, если вы сделаете foo из других объектов, таких как Class и Module. Примеры из всех ответов хороши, но вы должны работать с различными идеями или концепциями, чтобы действительно понять, что происходит с тем, как написан код. Итак, теперь у вас есть много условий, на которые нужно смотреть.
Singleton,
Класс,
Модуль,
самостоятельно,
Объект,
и Eigenclass был поднят, но Ruby не назвал объектные модели таким образом. Это больше похоже на Metaclass.
Ричард или __why показывает вам эту идею здесь.
http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html
И если удары вас прочь, попробуйте поискать Ruby Object Model в поиске.
Два видео, которые я знаю на YouTube, - это Дэйв Томас и Питер Купер. Они тоже пытаются объяснить эту концепцию. Дэйву потребовалось долгое время, чтобы не волноваться.
Я все еще работаю над этим. Зачем еще я здесь?
Спасибо за ваш вопрос.
Также взгляните на стандартную библиотеку. Он имеет модуль Singleton как FYI.
Это очень хорошо.
https://www.youtube.com/watch?v=i4uiyWA8eFk
Ответ 7
Недавно была написана статья об этом в среде, однако я думаю, что принятый ответ также хорош. Это может просто предоставить альтернативное объяснение для других, нуждающихся в помощи: https://medium.com/rubycademy/understanding-the-eigenclass-in-less-than-5-minutes-dcb8ca223eb4