猴子修补对象会产生奇怪的结果

Posted

技术标签:

【中文标题】猴子修补对象会产生奇怪的结果【英文标题】:monkey patching Object produces strange results 【发布时间】:2012-01-24 17:47:38 【问题描述】:

我正在将to_hash 破解为 Object(我并不是说这是一个好主意,只是一个实验)。当我遇到一个奇怪的问题时,IO 停止工作。

#lib/object.rb
class Object
  def to_hash
    self.instance_variables.inject()  |hash,var| hash[var.to_s.delete("@")] = self.instance_variable_get(var); hash  
  end
end

#run_test1.rb
require_relative 'lib/Object'
require 'FileUtils'

puts 'run test'


#run_test2.rb
require_relative 'lib/Object'

File.open('test.txt', 'w') |f| f.write('this is a test')

在 run_test1 我得到一个

<internal:lib/rubygems/custom_require>:29:in `set_encoding': wrong number of arguments (0 for 1..2) (ArgumentError)
        from <internal:lib/rubygems/custom_require>:29:in `require'
        from <internal:lib/rubygems/custom_require>:29:in `require'
        from .../run_test1.rb:2:in `<main>'

在 run_test2 我得到

run_test2.rb:3:in `initialize': No such file or directory - test.txt (Errno::ENOENT
        from run_test2.rb:3:in `open'
        from run_test2.rb:3:in `<main>'

(如果文件存在,则表示文件未打开以进行写入)

虽然我对它的发生并不感到惊讶 - 只是好奇,这里发生了什么?理论上应该没问题,但是根本原因是什么。

相关信息:

ruby 1.9.2p290 (2011-07-09) [i386-mingw32] XP SP3 32 位 RUBYGEMS 版本:1.8.12

【问题讨论】:

谁会想到更改低级对象会产生意想不到的后果,疯了!要发现 为什么 它会以这种方式破坏事物(在 pry 下更令人兴奋),您甚至可能需要跟踪一些 C,以确定为什么 to_hash 会特别破坏事物——也许是什么else 试图定义它,但没有定义它,因为它已经存在。谁知道。 to_hashish 工作正常,因此显然与符号相关。 为什么要关闭/拒绝投票?想知道为什么这会破坏某些东西(尤其是它的方式)是有效的,即使感到惊讶有点好笑。 谢谢,当我继续打破其他东西的道路上时,我会调查 pry...看起来很有趣 使用 ruby​​ 1.9.3p0,run_test1 可以正常工作。 run_test2 没有。 【参考方案1】:

to_hash 方法用于识别强制为 Hash 的对象。从这个意义上说,它的行为类似于to_aryto_str。您实现的方法更像to_ato_s

很多 Ruby 代码,包括 Ruby 核心代码,都会检查 to_hash 以确定参数是否是选项哈希 (arg.respond_to? :to_hash),然后从那里遵循不同的执行路径。一些代码检查对象是否是真正的散列(Hash === arg),这会变得更加混乱。

您可能希望将您的方法命名为 to_h 或类似名称。

【讨论】:

以上是关于猴子修补对象会产生奇怪的结果的主要内容,如果未能解决你的问题,请参考以下文章

为啥减去这两次(在 1927 年)会产生奇怪的结果?

当我使用线程将内容打印到控制台时,为啥会产生奇怪的结果?

直接访问与在开发工具中读取对象时访问 javascript 属性会产生不同的结果

Yii 和 PHPUnit 使用 fluent/mockbuilder 模拟会产生奇怪的结果

猴子在Python的另一个模块中修补一个类

加载模型后更改优化器或lr会产生奇怪的结果