为什么在 ruby​​ 中创建元类?

2024-05-06

我正在尝试了解 Ruby 对象模型。我知道实例方法保存在类中而不是类的对象中,因为它消除了冗余。我读到,每当创建一个类时,也会为新创建的类创建一个元类。元类存储类方法。即该类的单例方法位于元类中。例如

class MyClass
  def hi
    'hi object'
  end

  def self.bye
    'bye singleton method'
  end
end

对于上面的 MyClass,还创建了一个元类(例如#MyClass)。现在方法“hi”是一个实例级方法,可以在 MyClass 的所有对象上调用。方法“bye”是 MyClass 的单例方法,它驻留在 #MyClass 中。之所以将“hi”保存在 MyClass 而不是 MyClass 的所有对象中(我认为是这样),是因为它避免了冗余。但是我们不能有多个名为 MyClass 的类。那么为什么不在 MyClass 中而不是在 #MyClass 中存储“再见”,因为我们不能有多个 MyClass。我完全不知道为什么会这样,我只是想了解其背后的原因。

- - -更新 - -

元类存储类信息,例如单例方法和其他内容。但是,由于类是单例对象(它是类 Class 的实例,并且是其类型的唯一对象),那么为什么不将所有信息保存在类本身而不是元​​类中。


只是为了超级清楚。

这是一个解释这个问题的快速 ruby​​ 脚本:

#!/usr/bin/env ruby
puts ObjectSpace.count_objects[:T_CLASS] #>> 471
class X
  def self.foo
  end
  def bar
  end
end
puts ObjectSpace.count_objects[:T_CLASS] #>> 473

这就是 OP 所说的“ObjectSpace.count_objects[:T_CLASS] 将计数增加 2”的含义。我们将这个额外的类称为 X 的单例类,因为这似乎是 Ruby 内部对它的称呼。

irb> X
=> X
irb> X.singleton_class
=> <Class: X>

请注意,#foo方法是一个实例方法X.singleton_class, not X.

irb> X.instance_methods(false)
=> [:baz]
irb> X.singleton_class.instance_methods(false)
=> [:foo]

那么为什么是:foo存储在X.singleton_class代替X?是不是永远只有一个X?

我认为主要原因是一致性。考虑以下有关普通实例对象的更简单的场景。

car = Car.new
def car.go_forth_and_conquer
end

正如 @mikej 精彩地解释的那样,这个新方法存储在 car 的单例类中。

irb> car.singleton_class.instance_methods(false)
=> [:go_forth_and_conquer]

类是对象

现在,类也是对象。每个类都是一个实例Class。因此,当一堂课(比如X) 被定义,ruby 实际上创建了一个实例Class,然后向实例添加方法(类似于我们所做的car上面。)例如,这是创建新类的另一种方法

Car = Class.new do
  def go_forth_and_conquer
    puts "vroom"
  end
end
Car.new.go_forth_and_conquer

因此,重用代码并以相同的方式执行会更容易(即保留foo in X.singleton_class。)这可能需要更少的努力,并且会导致更少的意外,因此没有人需要编写代码来处理Class实例与其他实例不同。

可能并不重要

您可能会想,如果 Ruby 没有用于实例的单例类Class,可能会节省一些内存。然而,在我看来,哪里bar实际上存储的是我们可能不应该依赖的实现细节。 Rubinius、MRI 和 JRuby 都可以以不同的方式存储方法和实例,只要行为一致即可。据我们所知,Ruby 可能有一个合理的实现,它不会急切地为类对象创建单例类,原因与您概述的完全相同,只要整体行为符合 ruby​​ 规范。 (例如,一个实际的单例类直到#singleton_class首先调用方法。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么在 ruby​​ 中创建元类? 的相关文章

  • 从哈希中删除 nil 值

    我希望从哈希中删除具有nil value article是一个存储每篇文章的类 并且attributes方法将文章存储为散列 预期结果 articles results author null title Former bar manage
  • Ruby 2 升级破坏了 Nokogiri 和/或 open-uri 编码?

    将 Rails3 2 Ruby 1 9 应用程序升级到 Rails3 2 Ruby 2 1 2 时 我有一个谜团需要解决 Nokogiri 似乎崩溃了 因为它使用 open uri 改变了它的行为 没有改变 gem 版本 只是改变 ruby
  • rspec 测试 has_many :through 和 after_save

    我有一个 我认为 相对简单的has many through与连接表的关系 class User lt ActiveRecord Base has many user following thing relationships has ma
  • 随机显示 NoMethodError:未定义的方法“空?”对于 0:Fixnum

    它在我的本地计算机上运行良好 但使用 Puma Web 服务器在 Heroku 上的rails admin 中出现以下错误 这是我使用 enumerize 的方式 enumerize date type in last date 0 beg
  • Base36 编码字符串?

    我一直在网上查找 但找不到解决此问题的方法 在 Python Ruby 或 Java 中 如何对以下字符串进行 Base 36 编码 nOrG9Eh0uyeilM8Nnu5pTywj3935kW 5 Ruby 以 36 为基数 s unpa
  • 如何在 Ruby 中转义单引号?

    我通过一个脚本 不是我的 将一些 JSON 传递到服务器 该脚本接受 JSON 作为字符串 JSON 的某些内容包含单引号 因此我想确保在传递给脚本之前对所有单引号进行转义 我已经尝试过以下方法 gt irb gt 1 9 3p194 00
  • 查找日期时间与今天日期匹配的记录 - Ruby on Rails

    我有一个交易表 需要查找日期与今天的日期匹配的记录 从 Rails 控制台 我需要匹配的日期字段如下所示 我已经分配了一条记录来进行测试 ruby 1 9 2 p0 gt deal start gt Tue 10 May 2011 00 0
  • Rails 未定义“2013-03-06”的方法“strftime”:字符串

    我收到错误 2013 03 06 的未定义方法 strftime 字符串 当尝试使用 strftime 从字符串 2013 03 06 正常显示日期 2013 年 6 月星期日 3 日或类似的日期 时 在我的 index html erb
  • 将 Rails 更新到特定版本

    如何将 Rails 更新到特定版本 我的本地计算机上有 Rails 3 2 2 但我需要更新到版本 3 2 3 如果我执行gem update rails 将会更新到最新的3 2 6版本 我怎样才能做到这一点 gem install rai
  • 如何使用 Nokogiri 将带有 & 符号的字符串放入 xml 文件中?

    我试图在 XML 文件中包含图像的 URL 并且 URL 查询字符串中的 符号被删除 bgdoc xpath Master each do elem part elem xpath Part inner text image imageha
  • Rails current_path 助手?

    我正在开发具有以下路由条件的 Rails 3 2 应用程序 scope locale locale de en do resources categories only index show get newest index as newe
  • Rails 中的代码片段应该放在哪里?

    我有这个代码片段 可以为 POST 生成签名 它的细节并不重要 但我想知道的是 由于它不是与模型相关的代码块 所以它确实可以在任何地方使用 在控制器中 在模型中 在视图助手中 即使在视图中 因此 我不确定在哪里 甚至更大的问题是 一旦将其放
  • Watir 不会下载 PDF,只能在查看器中打开

    我试图用 Selenium 进行测试 但无法下载 pdf pdf 一直打开 参见我的另一篇文章 RUBY Selenium Webdriver 设置为下载 pdf 文件而不是打开它们 https stackoverflow com ques
  • 机架测试失败:JSON 请求尚未响应

    我正在尝试为我的 Ruby 项目创建一个 JSON API 如下所示Ticketee https github com rails3book ticketeeYehuda Katz 书中提供的示例Rails 3 实际应用 http www
  • Capybara::ElementNotFound:无法找到字段“标题”

    我无法解决这个问题 请帮我 它给了我找不到元素的错误 规格 功能 todos create spec rb require spec helper describe Creating todos do let user FactoryGir
  • 帮助重构这个讨厌的 Ruby if/else 语句

    所以我有这个大而多毛的 if else 语句 我将跟踪号码传递给它 然后它确定它是什么类型的跟踪号码 我怎样才能简化这件事 具体来说就是想减少代码行数 if num length lt 8 tracking service false el
  • Rails has_many 通过带有附加属性的表单

    我正在尝试创建一个表单 允许用户向活动添加 编辑 删除位置 我目前找到的所有例子要么是HABTM表单 不允许编辑存在于表单中的附加属性 has many through配置 或仅列出现有关系 下面的图片显示了我想要完成的任务 该列表将显示每
  • 如何清除 ruby​​ 中 rspec 测试之间的类变量

    我有以下课程 我想确保类 url 只为所有实例设置一次 class DataFactory url nil def initialize begin if url nil Rails logger debug Setting url url
  • 使用自定义 gem 在 Dreamhost/Passenger 上部署 Sinatra 应用程序

    我有一个 Sinatra 应用程序 正在尝试在 Dreamhost 上运行 该应用程序利用 pony 发送电子邮件 为了让应用程序从一开始就启动并运行 在添加小马之前 我必须gem unpack rack and gem unpack si
  • 回形针:从带扩展名的 url 上传

    我想通过 S3 存储上的回形针从 URL 上传图片 我与 Ruby 1 9 3 Rails 3 2 6 paperclip 3 1 3 aws sdk 1 3 9 我有我的图片模型 class Asset has attached file

随机推荐