【问题标题】:Ruby Class Methods vs. Methods in EigenclassesRuby 类方法与 Eigenclasses 中的方法
【发布时间】:2011-05-12 03:33:25
【问题描述】:

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

否则有什么区别?

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"

【问题讨论】:

    标签: ruby class overriding class-method eigenclass


    【解决方案1】:

    这两种方法是等价的。 '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
    

    【讨论】:

    • 这是一个关于单身人士的绝妙答案
    【解决方案2】:

    在 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(特征、元、ghost 或任何您想称呼它们的)方法,在您的示例中为 X。这个话题是元编程的一部分,这是一个有趣的话题,如果你已经使用 Ruby 一段时间了,你应该看看。 Pragmatic Programmers 有一个很棒的 book 元编程,如果您对该主题感兴趣,您一定要看看。

    【讨论】:

    • 不同意“没有类方法之类的东西”。 Smalltalk 已经存在了很长时间,并且也是纯 OO 并且他们一直使用类方法术语。说类方法比“单例”更容易混淆,因为后者是一种设计模式,而不是语言的属性。
    • 我可能会在这里获得死灵魔法奖,但我强烈同意“没有类方法之类的东西”。如果您在对象的特征类上定义了一个方法,并且该对象是Dog 的一个实例,则您不能将该方法称为狗方法。
    • 如果您使用:private_class_method 函数标记方法,它肯定会试图让您将其视为类方法。
    【解决方案3】:

    另一个死灵法师在这里挖掘这个老问题......你可能不知道的一件事是,将类方法标记为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)
    

    【讨论】:

      【解决方案4】:

      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

      以上两个示例都用于说明单例方法的工作原理。但是,有一种更简单的方法来定义单例方法:使用名为 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

      this post about Ruby Classes了解更多信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-05
        • 1970-01-01
        • 2015-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多