В Ruby есть какие-либо связанные приложения синтаксиса: class << self... end

class << self
attr_accessor :n, :totalX, :totalY
end

Синтаксис выше используется для определения переменных экземпляра класса. Но когда я думаю о синтаксисе, это не имеет для меня никакого смысла, поэтому мне интересно, используется ли этот тип синтаксиса для любых других типов определений. Здесь моя точка зрения:

class << self

Оператор append обычно означает "добавить то, что справа от объекта слева". Но в контексте этого блока, как это добавляет "помещать содержимое этого блока в определение экземпляра класса, а не экземпляра"?

По той же причине я путаюсь, почему в одном контексте класс < < self может определять переменные экземпляра класса, а в другом - создавать переменные класса, такие как здесь:

class Point
  # Instance methods go here
  class << self
    # Class methods go here
  end
end

Ответ 1

в Ruby вы можете повторно открыть существующие классы и добавить методы. То есть вы можете сказать:

class Foo
  def bob
    return "hello from bob"
  end
end

эти методы сохраняются где-то во внутреннем словаре (возможно, переменной экземпляра) класса Foo -класс (который является всего лишь экземпляром класса Class и поэтому имеет переменные экземпляра)

Но удивительным является то, что вы также можете добавлять методы к экземплярам существующих объектов

foo = Foo.new
foo2 = Foo.new

def foo.fred
  return "I am fred"
end


foo.fred  #=> "I am fred"
foo2.fred #=> NoMethodError

но Где этот метод фактически хранится?

Выключает Ruby создает новый класс за кулисами (иногда называемый singleton class, metaclass или eigenclass), который вставлен в наследственную иерархию между классом Foo и его экземпляром.

Таким образом, отношение наследования выглядит следующим образом:

foo < (eigenclass of foo) < Foo < Class

(если вы скажете foo.superclass, вы не увидите одноэлементный класс)

class << X -syntax - это способ добраться до этого специального класса, чтобы вы могли манипулировать им напрямую. Следующие кодовые блоки в точности эквивалентны:

def foo.bar
  return "xy"
end

# is exactly the same as

class << foo
  def bar
    return "xy"
  end
end

Таким образом, сходство между class Foo < Bar и class << Foo не является случайным, происходит наследование в обоих.

Подумайте о class << X как "открыть метакласс X"

В Ruby следует помнить, что сами классы - это просто объекты. (Экземпляры класса Class), поэтому, если вы скажете:

class Foo
  class << self
    def k
      return "x"
    end
  end
end

(self привязан к Foo в этом кодовом блоке), поэтому k является методом экземпляра eigenclass Foo, что делает его методом класса для Foo

все это объясняется более четко в главе о классах Pickaxe (к сожалению, веб-версия не содержит диаграмм) и _whys Видя метаклассы ясно

Ответ 2

Подумайте о классе как содержащем словарь членов, включая все аксессоры и переменные экземпляра. Когда вы говорите классу "добавить" к "самому", вы говорите "добавьте их в словарь членов класса".

Я дам, чтобы обозначение было немного странным.

Ответ 3

на самом деле сбивает с толку думать об этом с точки зрения оператора "append". лучший способ взглянуть на это состоит в том, что так же, как class Foo открывает класс Foo, т.е. устанавливает "я" к объекту класса Foo, создавая его, если необходимо, поэтому class << self открывает собственный объект текущего ' сам "объект. обратите внимание, что это не ограничивается self - для любой панели объектов, вы можете сказать, что класс < бар, чтобы открыть значок этого объекта.

class A
  def hello
    print "hello world"
  end
end

a = A.new
b = A.new

class << a
  def goodbye
    print "goodbye cruel world"
  end
end

a.hello
b.hello
a.goodbye
b.goodbye