ruby克隆对象

ruby克隆对象,ruby,class,clone,dup,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[:veri

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

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}>
有办法解决这个问题吗?

您需要.clone或者.dup

但这取决于您的目的,但在本例中,您可能需要.clone 看

主要区别在于.clone还复制对象的单例方法和冻结状态

在旁注中,您还可以更改

options[:path] = '/' if options[:path].nil? # you don't need "== true" 
你想要.clone或者.dup

但这取决于您的目的,但在本例中,您可能需要.clone 看

主要区别在于.clone还复制对象的单例方法和冻结状态

在旁注中,您还可以更改

options[:path] = '/' if options[:path].nil? # you don't need "== true" 

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

就在这里:

test = Http.new({})
test2 = test
您没有两个Http实例,只有一个。只有两个变量指向同一个实例

你可以改成这个,这样你就不会有问题了

test = Http.new({})
test2 = Http.new({})
但是,如果使用共享选项参数,则会遇到以下问题:

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

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

就在这里:

test = Http.new({})
test2 = test
您没有两个Http实例,只有一个。只有两个变量指向同一个实例

你可以改成这个,这样你就不会有问题了

test = Http.new({})
test2 = Http.new({})
但是,如果使用共享选项参数,则会遇到以下问题:

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

我能问一下你想用这个猴子补丁做什么吗?我正在测试你的代码,但它们似乎不起作用。我能问一下你的猴子补丁到底想做什么吗?我正在尝试测试你的代码,但它们似乎不起作用。这里有好的方面,尽管不清楚OP的最终目的是如何处理这个猴子补丁。我甚至无法让get方法工作。这里有好的方面,尽管还不清楚OP的最终目的是用这个猴子补丁做什么。我甚至无法让get方法发挥作用。