Ruby中'self.method_name'和'class << self'之间的区别

Posted

技术标签:

【中文标题】Ruby中\'self.method_name\'和\'class << self\'之间的区别【英文标题】:Difference between 'self.method_name' and 'class << self' in RubyRuby中'self.method_name'和'class << self'之间的区别 【发布时间】:2011-01-02 19:00:10 【问题描述】:

我试图将一个类的实例化限制为一个(不使用单例),但我做不到。我尝试使用类变量(@@)但没有运气。 我用谷歌搜索了一下,发现了这个:

class A 
  @count = 0 

  class << self 
    attr_accessor :count 
  end

  def initialize val 
    @a = val 
    self.class.count += 1 
  end 
end 

a=A.new 42 
b=A.new 43

我搜索了 'class ' 的解释,希望能找到一个更好的(或者只是一个更简单和干净的),但再次失败,没有运气。 最后,经过一些测试,我得出结论 'class ' 只是一个块包装器,您可以在其中定义 class 方法。 那么,这是正确的吗?

问候!

【问题讨论】:

你的第一句话真的没有意义,因为如果你的类只能有一个实例,那么它就是一个单例,不管你如何实现该行为。还是你的意思是单例类(eigenclass)? @John,我假设他的意思是标准库中包含的Singleton 类。 【参考方案1】:

class &lt;&lt; self 表示法打开了对象的特征类。 eigenclass 是一个匿名类,它存储特定于实例的行为。在类的情况下,特征类有时称为元类。

Ruby 使用特征类来实现所谓的“类方法”(也称为静态方法)。

一个类(正如 moritz 所说)在 Ruby 中也是一个对象,就它是一个对象而言,它也有一个类。 Ruby 中一个类的类称为Class

任何语言中的“类方法”都是以类为接收者的方法——即直接在类本身上调用该方法。

但是,为了在接收器上调用方法,必须在该接收器的类上定义该方法。对于类,“类方法”可以实现为Class 类的实例方法。

但是在Class 上定义实例方法意味着所有类都可以访问该类方法,这并不理想。

输入特征类,如前所述,对象的特征类是一个特殊的类,它存储该对象独有的方法。在类的情况下,特征类是Class 类的子类,并且是该类的直接类。

因此,Ruby 中的“类方法”只是在类的特征类上定义的“实例方法”。

def MyClass.my_method 表示法实际上在 MyClass 的特征类上定义了 my_method。如果您使用这种表示法,您可以(暂时)在没有真正理解特征类的情况下通过,因为您可以欺骗自己认为这只是 Ruby 定义“静态方法”的方式,并继续认为 Ruby 的类模型类似于 Java。但是,class &lt;&lt; self 表示法不允许这样的解释,您必须接受特征类的现实。

总之,“类方法”实际上是在特征类上定义的“实例方法”,class &lt;&lt; self 让您可以访问特征类。

更多阅读请查看以下链接:

http://banisterfiend.wordpress.com/2008/11/25/a-complete-ruby-class-diagram/

http://banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/

http://www.klankboomklang.com/2007/09/21/the-singleton-class/

【讨论】:

很好的解释——我在谷歌上搜索类 这是一个相关的问题:当您在特征类内部(即在 class &lt;&lt; self 块内)使用 self.method_name 定义方法时会发生什么。这种方法最终会在哪里?我不是在问这是否是个好主意,甚至是推荐……只是好奇它最终会出现在什么对象上。 我想知道@GuyPaddock 问题的答案。在class &lt;&lt; self 中使用class &lt;&lt; self 确实将您置于特征类的特征类 中,展示了Ruby 的内部一致性。由于 eigenclass' 是 instance_of?(Class),因此它具有可用的 singleton_class 方法。因此,我们可以在单例类上定义单例类... 您可以使用eigenclass = class Dog; class &lt;&lt; self; self; end; endeigen_eigenclass = class Dog; class &lt;&lt; self; class &lt;&lt; self; self; end; end; end 进行测试。请注意eigenclass != eigen_eigencalss #=&gt; trueeigenclass.singleton_class == eigen_eigenclass #=&gt; true【参考方案2】:

从技术上讲,您是在类的元类上定义一个方法,而不是在类本身上。 Yehuda Katz 在这里对 Ruby 中的元类进行了很好的解释:http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/

【讨论】:

_why也写了一篇好文章:ruby-metaprogramming.rubylearning.com/html/…【参考方案3】:

主题行与问题的正文不太匹配。我将解决主题行中表达的问题:

它们是同义词。

def self.foo
    ...
end

只是简写

class << self
    def foo
        ...
    end
end

【讨论】:

不是“只是”。在class &lt;&lt; self 块中,您可以使用privateprotected【参考方案4】:

你的结论是对的。基本上,您必须记住,即使类也是 ruby​​ 中的对象,因此也有实例。而使用 class

【讨论】:

我刚刚修改了字符串类中的 ' wtf?这种解释是完全奇怪的。您说“类是 ruby​​ 中的对象,因此具有实例”,我认为您的意思是说类是实例?因为一个类个实例并不奇怪(这是一个类的本质)。此外,您说“类 类是实例?我不太确定谁的理解不完整。如果您能花时间提供一个不那么奇怪的答案来帮助我下次做对,那将会很有帮助。 查看我在回答中提供的链接,以全面了解执行“class @mortiz,在下面回答。是的,类是实例(类及其元类的实例);)

以上是关于Ruby中'self.method_name'和'class << self'之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

如果使用实例化对象,来为类动态的添加一个 字符串形式的 方法。

ruby 在Ruby中拆分和连接文件

ruby 在Ruby中尝试使用分叉和unix套接字

ruby 中的 Mandrill 验证,在 php 和 ruby​​ 之间的翻译中丢失

如何在 ruby​​ on rails 中访问 rails 助手和嵌入资产 javascript 文件中的 ruby​​?

ruby 使用ruby从您的照片中删除位置信息和其他元数据