14

类方法和该类的特征类(或元类)中的方法是否只是定义一件事的两种方法?

否则,有什么区别?

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

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

以任何方式做X.aX.b表现不同?

我认识到我可以通过打开 eigenclass 来覆盖或别名类方法:

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

4 回答 4

11

这两种方法是等价的。'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
于 2010-11-18T16:22:56.360 回答
6

在 Ruby 中,确实没有类方法之类的东西。由于在 Ruby 中一切都是对象(包括类),所以当您说 时def self.class_method,您实际上只是在类的实例上定义了一个单例方法Class。所以回答你的问题,说

class X
  def self.a
    puts "Hi"
  end

  class << self
    def b
      puts "there"
    end
  end
end

X.a # => Hi
X.b # => there

是同一件事的两种说法。这两种方法都只是在 Class 对象的实例中定义的 singeton(特征、元、幽灵或任何你想调用它们的)方法,在你的示例中是X. 这个主题是元编程的一部分,这是一个有趣的主题,如果你已经使用 Ruby 一段时间了,你应该看看。The Pragmatic Programmers 有一关于元编程的好书,如果你对这个主题感兴趣,你绝对应该看看。

于 2010-11-19T04:08:27.790 回答
3

另一个死灵法师在这里挖掘这个老问题......您可能不知道的一件事是,将类方法标记为private(使用 private 关键字而不是:private_class_method)与将 eigenclass 方法标记为这样不同。:

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)
于 2016-04-12T14:49:47.690 回答
1

Ruby 中使用的大多数实例方法都是全局方法。这意味着它们在定义它们的类的所有实例中都可用。相反,单例方法是在单个对象上实现的。

有明显的矛盾。Ruby 将方法存储在类中,所有方法都必须与一个类相关联。定义单例方法的对象不是类(它是类的实例)。如果只有类可以存储方法,那么对象如何存储单例方法?创建单例方法时,Ruby 会自动创建一个匿名类来存储该方法。这些匿名类称为元类,也称为单例类或特征类。单例方法与元类相关联,而元类又与定义了单例方法的对象相关联。

如果在单个对象中定义了多个单例方法,则它们都存储在同一个元类中。

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 方法是在 Zen 类的 z1 实例中定义的,而不是在 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'…

在上面的例子中,class << z1 改变了当前的 self 指向 z1 对象的元类;然后,它在元类中定义 say_hello 方法。

上述两个示例都用于说明单例方法的工作原理。但是,有一种更简单的方法来定义单例方法:使用名为 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 类的元类。当一个方法在没有显式接收者(将在其上定义该方法的类/对象)的情况下定义时,它被隐式定义在当前范围内,即 self 的当前值。因此,stuff 方法是在 Zabuton 类的元类中定义的。上面的例子只是定义类方法的另一种方式。

在这篇关于 Ruby 类的文章中阅读更多内容。

于 2016-06-26T18:22:30.213 回答