Методы класса Ruby против методов в собственных классах - PullRequest
14 голосов
/ 18 ноября 2010

Являются ли методы и методы класса в собственном классе (или метаклассе) этого класса просто двумя способами определить одну вещь?

В противном случае, в чем различия?

class X
  # class method
  def self.a
    "a"
  end

  # eigenclass method
  class << self
    def b
      "b"
    end
  end
end

Do X.a и X.b ведут себя по-разному в любом случае?

Я понимаю, что я могу перезаписать или псевдонимметоды класса, открыв собственный класс:

irb(main):031:0> class X; def self.a; "a"; end; end
=> nil
irb(main):032:0> class X; class << self; alias_method :b, :a; end; end
=> #<Class:X>
irb(main):033:0> X.a
=> "a"
irb(main):034:0> X.b
=> "a"
irb(main):035:0> class X; class << self; def a; "c"; end; end; end
=> nil
irb(main):036:0> X.a
=> "c"

Ответы [ 4 ]

11 голосов
/ 18 ноября 2010

Два метода эквивалентны. Версия 'eigenclass' полезна для использования методов attr_ *, например:

class Foo
  @instances = []
  class << self;
    attr_reader :instances
  end
  def initialize
    self.class.instances << self
  end
end

2.times{ Foo.new }
p Foo.instances
#=> [#<Foo:0x2a3f020>, #<Foo:0x2a1a5c0>]

Вы также можете использовать define_singleton_method для создания методов в классе:

Foo.define_singleton_method :bim do "bam!" end
6 голосов
/ 19 ноября 2010

В Ruby действительно нет таких вещей, как методы класса.Поскольку в Ruby все является объектом (включая классы), когда вы говорите def self.class_method, вы просто определяете одноэлементный метод для экземпляра класса Class.Поэтому, чтобы ответить на ваш вопрос, сказать «1003 * * 1004» * «1005 *» - это два способа сказать одно и то же.Оба эти метода - просто одиночные (собственные, мета, призрачные или как вы хотите их вызывать) методы, определенные в экземпляре вашего объекта Class, который в вашем примере был X.Эта тема является частью метапрограммирования, что является забавной темой, которую вы должны проверить, если вы некоторое время использовали Ruby.У прагматичных программистов есть отличная книга по метапрограммированию, на которую обязательно стоит взглянуть, если вам интересна эта тема.

3 голосов
/ 12 апреля 2016

Еще один некромант здесь, чтобы раскрыть этот старый вопрос ... Одна вещь, о которой вы можете не знать, это то, что пометка метода класса как private (использующая ключевое слово private вместо :private_class_method) отличается от маркировки собственного класса метод как таковой. :

class Foo
  class << self
    def baz
      puts "Eigenclass public method."
    end

    private
    def qux
      puts "Private method on eigenclass."
    end
  end
  private
  def self.bar
    puts "Private class method."
  end
end

Foo.bar
#=> Private class method.
Foo.baz
#=> Eigenclass public method.
Foo.qux
#=> NoMethodError: private method `qux' called for Foo:Class
#   from (irb)

Следующий пример будет работать так, как задумал предыдущий:

class Foo
  class << self
    def baz
      puts "Eigen class public method."
    end

    private
    def qux
      puts "Private method on eigenclass."
    end
  end
  def bar
    puts "Private class method."
  end
  private_class_method :bar
end
Foo.bar
#=> NoMethodError: private method `bar' called for Foo:Class
#     from (irb)
Foo.baz
#=> Eigen class public method.
Foo.qux
#=> NoMethodError: private method `qux' called for Foo:Class
#     from (irb)
1 голос
/ 26 июня 2016

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

Существует очевидное противоречие. Ruby хранит методы в классах, и все методы должны быть связаны с классом. Объект, для которого определен одноэлементный метод, не является классом (это экземпляр класса). Если только классы могут хранить методы, как объект может хранить одноэлементный метод? При создании одноэлементного метода Ruby автоматически создает анонимный класс для хранения этого метода. Эти анонимные классы называются метаклассами, также известными как одноэлементные классы или собственные классы. Метод singleton связан с метаклассом, который, в свою очередь, связан с объектом, для которого был определен метод singleton.

Если в одном объекте определены несколько одноэлементных методов, все они хранятся в одном метаклассе.

class Zen
end

z1 = Zen.new
z2 = Zen.new

def z1.say_hello  # Notice that the method name is prefixed with the object name
  puts "Hello!"
end

z1.say_hello    # Output: Hello!
z2.say_hello    # Output: NoMethodError: undefined method `say_hello'…

В приведенном выше примере метод say_hello был определен в экземпляре z1 класса Zen, но не в экземпляре z2.

В следующем примере показан другой способ определения одноэлементного метода с тем же результатом.

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 в метаклассе. </p>

Оба приведенных выше примера служат для иллюстрации работы одноэлементных методов. Однако существует более простой способ определения одноэлементного метода: использование встроенного метода define_singleton_method.

class Zen
end

z1 = Zen.new
z2 = Zen.new

z1.define_singleton_method(:say_hello) { puts "Hello!" }

z1.say_hello    # Output: Hello!
z2.say_hello    # Output: NoMethodError: undefined method `say_hello'…

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

Еще один пример:

class Zabuton
  class << self
    def stuff
      puts "Stuffing zabuton…"
    end
  end
end

Все объекты могут иметь метаклассы. Это означает, что у классов также могут быть метаклассы. В приведенном выше примере class << self изменяет self, поэтому оно указывает на метакласс класса Zabuton. Когда метод определен без явного получателя (класс / объект, для которого будет определен метод), он неявно определяется в текущей области, то есть в текущем значении себя. Следовательно, метод stuff определен в метаклассе класса Zabuton. Приведенный выше пример является еще одним способом определения метода класса. </p>

Подробнее на этот пост о Ruby Classes .

...