В Ruby есть связанные приложения синтаксиса: class << self ... end - PullRequest
11 голосов
/ 22 мая 2009
class << self
attr_accessor :n, :totalX, :totalY
end

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

class << self

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

По той же причине, по которой я запутался, почему в одном контексте класс

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

Ответы [ 3 ]

19 голосов
/ 22 мая 2009

в 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 создает за кулисами новый класс (иногда называемый синглтон-класс , метакласс или eigenclass ), который вставляется в наследственную иерархию между классом Foo и его экземпляром.

Итак, отношения наследования выглядят так:

foo < (eigenclass of foo) < Foo < Class

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

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

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 является экземпляром метода собственного класса Foo, что делает его методом класса для Foo

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

2 голосов
/ 22 мая 2009

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

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

1 голос
/ 22 мая 2009

на самом деле сбивает с толку представление об этом в терминах оператора «добавления». лучший способ взглянуть на это так: class Foo открывает класс Foo, то есть он устанавливает 'self' для объекта класса Foo, создавая его при необходимости, поэтому class << self открывает собственный класс текущего ' Я объект обратите внимание, что он не ограничен self - для любой панели объектов вы можете сказать class << bar, чтобы открыть собственный класс этого объекта. </p>

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
...