ruby - ruby 克隆对象

原文 标签 ruby class clone dup

我需要克隆一个现有的对象并改变那个克隆的对象。
问题是我的更改更改更改了原始对象。
代码如下:

require "httparty"

class Http
  attr_accessor :options
  attr_accessor :rescue_response
  include HTTParty
  def initialize(options)
    options[:path] = '/' if options[:path].nil? == true
    options[:verify] = false
    self.options = options

    self.rescue_response = {
      :code => 500
    }
  end

  def get
    self.class.get(self.options[:path], self.options)
  end

  def post
    self.class.post(self.options[:path], self.options)
  end

  def put
    self.class.put(self.options[:path], self.options)
  end

  def delete
    self.class.put(self.options[:path], self.options)
  end

end

脚本:
test = Http.new({})

test2 = test

test2.options[:path] = "www"

p test2
p test

输出:
#<Http:0x00007fbc958c5bc8 @options={:path=>"www", :verify=>false}, @rescue_response={:code=>500}>
#<Http:0x00007fbc958c5bc8 @options={:path=>"www", :verify=>false}, @rescue_response={:code=>500}>

有没有办法解决这个问题?

最佳答案

你甚至不需要在这里克隆,只需要创建一个新实例。
就在这里:

test = Http.new({})
test2 = test

你没有两个Http实例,只有一个只有两个变量指向同一个实例。
你可以改成这个,你就不会有问题了。
test = Http.new({})
test2 = Http.new({})

但是,如果您使用了sharedoptions参数,则会遇到一个问题:
options = { path: nil }
test = Http.new(options)

# options has been mutated, which may be undesirable
puts options[:path] # => "/"

为了避免这种“副作用”,可以将initialize方法更改为使用选项的克隆:
def initialize(options)
  options = options.clone
  # ... do other stuff
end

您还可以使用splat运算符,它稍微有点神秘,但可能更习惯用法:
def initialize(**options)
  # do stuff with options, no need to clone
end

然后调用构造函数,如下所示:
options = { path: nil }
test = Http.new(**options)
puts test.options[:path] # => "/"

# the original hasn't been mutated
puts options[:path] # => nil

相关文章:

ruby-on-rails - 使用除外删除哈希键

ruby-on-rails - Rails中数字的本地化

java - 为什么这个吐司不应该出现?

oop - 面向对象编程-何时添加新类?

java - 深度复制图结构

javascript - jQuery .clone(true,true)不克隆事件

git - git clone更改文件修改时间

ruby-on-rails - 没有将nil隐式转换为字符串设计

ruby - 为什么serverspec连接到本地主机而不是远程主机

python - 在不使用多个函数的情况下使用python评估数学表达式的算法