Класс << Собственная идиома в Ruby
Что значит class << self
делать в рубине?
6 ответов
Во-первых, class << foo
синтаксис открывается foo
Синглтон-класс (собственный класс). Это позволяет вам специализировать поведение методов, вызываемых для этого конкретного объекта.
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
одноэлементный класс, так что методы могут быть переопределены для текущего 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
), поведение меняется в зависимости от состояния.
Я нашел супер простое объяснение о class << self
, Eigenclass
и другой тип methods
в этом блоге.
В 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
Обычно методы экземпляра являются глобальными методами. Это означает, что они доступны во всех экземплярах класса, в котором они были определены. Напротив, одноэлементный метод реализован на одном объекте.
Ruby хранит методы в классах, и все методы должны быть связаны с классом. Объект, для которого определен одноэлементный метод, не является классом (это экземпляр класса). Если только классы могут хранить методы, как объект может хранить одноэлементный метод? При создании одноэлементного метода Ruby автоматически создает анонимный класс для хранения этого метода. Эти анонимные классы называются метаклассами, также известными как одноэлементные классы или собственные классы. Одноэлементный метод связан с метаклассом, который, в свою очередь, связан с объектом, для которого был определен одноэлементный метод.
Если в одном объекте определены несколько одноэлементных методов, все они хранятся в одном и том же метаклассе.
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 изменяет текущее "я", указывая на метакласс объекта z1; затем он определяет метод say_hello в метаклассе.
Классы также являются объектами (экземплярами встроенного класса под названием Class). Методы класса - это не более чем одноэлементные методы, связанные с объектом класса.
class Zabuton
class << self
def stuff
puts "Stuffing zabuton…"
end
end
end
Все объекты могут иметь метаклассы. Это означает, что у классов также могут быть метаклассы. В приведенном выше примере class << self изменяет self, поэтому оно указывает на метакласс класса Zabuton. Когда метод определен без явного получателя (класс / объект, для которого будет определен метод), он неявно определяется в текущей области, то есть в текущем значении себя. Следовательно, метод stuff определен в метаклассе класса Zabuton. Приведенный выше пример является еще одним способом определения метода класса. ИМХО, лучше использовать синтаксис def self.my_new_clas_method для определения методов класса, так как это облегчает понимание кода. Приведенный выше пример был включен, чтобы мы понимали, что происходит, когда сталкиваемся с синтаксисом класса << self.
Дополнительную информацию можно найти в этом посте о Ruby Classes.
Что делает класс << вещь:
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
метод экземпляра класса синглтона :a
, Это можно было сделать с помощью класса << hi. hi
"s #singleton_class
имеет все методы экземпляра hi
"s #class
есть, и, возможно, еще немного (:a
Вот).
[Экземпляры вещей #class
а также #singleton_class
может применяться непосредственно к вещи. когда ruby видит thing.a, он сначала ищет: определение метода в thing.singleton_class.instance_methods, а затем в thing.class.instance_methods]
Кстати, они называют синглтон-класс объекта == метакласс == собственный класс.
Одноэлементный метод - это метод, который определяется только для одного объекта.
Пример:
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's methods of SomeClass"
puts SomeClass.singleton_methods
puts '------------------------------------------'
puts "Singleton's methods of test_obj"
puts test_obj.singleton_methods
Синглтон методы SomeClass
тестовое задание
Синглтон методы test_obj
test_2
test_3
Фактически, если вы пишете какие-либо расширения C для своих проектов Ruby, на самом деле есть только один способ определить метод Module.
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 из других объектов, таких как класс и модуль. С примерами из всех ответов приятно играть, но вам нужно работать с различными идеями или концепциями, чтобы действительно понять, что происходит с тем, как написан код. Так что теперь у вас есть много терминов, чтобы пойти посмотреть.
Singleton, Class, Module, self, Object и Eigenclass были подняты, но Ruby не называет объектные модели таким образом. Это больше похоже на метакласс. Ричард или __ почему показывает вам идею здесь. http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html И, если вас унесет, попробуйте поискать Ruby Object Model в поиске. Два видео, которые я знаю на YouTube, это Дейв Томас и Питер Купер. Они тоже пытаются объяснить эту концепцию. Дэйву понадобилось много времени, чтобы получить его, так что не волнуйтесь. Я все еще работаю над этим тоже. Зачем еще я буду здесь? Спасибо за ваш вопрос. Также взгляните на стандартную библиотеку. Он имеет одноэлементный модуль, как FYI.
Это довольно хорошо. https://www.youtube.com/watch?v=i4uiyWA8eFk