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 << self
表示法打开了对象的特征类。 eigenclass 是一个匿名类,它存储特定于实例的行为。在类的情况下,特征类有时称为元类。
Ruby 使用特征类来实现所谓的“类方法”(也称为静态方法)。
一个类(正如 moritz 所说)在 Ruby 中也是一个对象,就它是一个对象而言,它也有一个类。 Ruby 中一个类的类称为Class
。
任何语言中的“类方法”都是以类为接收者的方法——即直接在类本身上调用该方法。
但是,为了在接收器上调用方法,必须在该接收器的类上定义该方法。对于类,“类方法”可以实现为Class
类的实例方法。
但是在Class
上定义实例方法意味着所有类都可以访问该类方法,这并不理想。
输入特征类,如前所述,对象的特征类是一个特殊的类,它存储该对象独有的方法。在类的情况下,特征类是Class
类的子类,并且是该类的直接类。
因此,Ruby 中的“类方法”只是在类的特征类上定义的“实例方法”。
def MyClass.my_method
表示法实际上在 MyClass 的特征类上定义了 my_method
。如果您使用这种表示法,您可以(暂时)在没有真正理解特征类的情况下通过,因为您可以欺骗自己认为这只是 Ruby 定义“静态方法”的方式,并继续认为 Ruby 的类模型类似于 Java。但是,class << self
表示法不允许这样的解释,您必须接受特征类的现实。
总之,“类方法”实际上是在特征类上定义的“实例方法”,class << 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 << self
块内)使用 self.method_name
定义方法时会发生什么。这种方法最终会在哪里?我不是在问这是否是个好主意,甚至是推荐……只是好奇它最终会出现在什么对象上。
我想知道@GuyPaddock 问题的答案。在class << self
中使用class << self
确实将您置于特征类的特征类 中,展示了Ruby 的内部一致性。由于 eigenclass' 是 instance_of?(Class)
,因此它具有可用的 singleton_class
方法。因此,我们可以在单例类上定义单例类...
您可以使用eigenclass = class Dog; class << self; self; end; end
和eigen_eigenclass = class Dog; class << self; class << self; self; end; end; end
进行测试。请注意eigenclass != eigen_eigencalss #=> true
和eigenclass.singleton_class == eigen_eigenclass #=> 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 << self
块中,您可以使用private
和protected
。【参考方案4】:
你的结论是对的。基本上,您必须记住,即使类也是 ruby 中的对象,因此也有实例。而使用 class
【讨论】:
我刚刚修改了字符串类中的 ' wtf?这种解释是完全奇怪的。您说“类是 ruby 中的对象,因此具有实例”,我认为您的意思是说类是实例?因为一个类有个实例并不奇怪(这是一个类的本质)。此外,您说“类 类是实例?我不太确定谁的理解不完整。如果您能花时间提供一个不那么奇怪的答案来帮助我下次做对,那将会很有帮助。 查看我在回答中提供的链接,以全面了解执行“class @mortiz,在下面回答。是的,类是实例(类及其元类的实例);)以上是关于Ruby中'self.method_name'和'class << self'之间的区别的主要内容,如果未能解决你的问题,请参考以下文章
如果使用实例化对象,来为类动态的添加一个 字符串形式的 方法。
ruby 中的 Mandrill 验证,在 php 和 ruby 之间的翻译中丢失
如何在 ruby on rails 中访问 rails 助手和嵌入资产 javascript 文件中的 ruby?