Класс << 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 есть три типа методов, которые могут быть применены к классу:

  1. Методы экземпляра
  2. Одиночные методы
  3. Методы класса

Методы экземпляра и методы класса почти аналогичны их одноименным в других языках программирования.

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