【问题标题】:ruby clone an object红宝石克隆一个对象
【发布时间】:2019-03-18 04:08:52
【问题描述】:

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

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}>

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

【问题讨论】:

  • 我能问一下你想用这个猴子补丁做什么吗?我正在尝试测试您的代码,但它们似乎不起作用。

标签: ruby class clone dup


【解决方案1】:

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

就在这里:

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

你没有两个 Http 实例,你只有一个。你只有两个变量指向同一个实例。

你可以改成这样,就不会出现问题了。

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

但是,如果您使用了共享的 options 参数,那么您就会遇到问题:

options = { path: nil }
test = Http.new(options)

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

为避免这种“副作用”,您可以更改初始化方法以使用选项的克隆:

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 方法工作。
【解决方案2】:

你想要.clone或者.dup

test2 = test.clone

但取决于你的目的,但在这种情况下,你可能想要.cloneWhat's the difference between Ruby's dup and clone methods?

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

顺便说一句,你也可以改变

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

【讨论】:

    猜你喜欢
    • 2022-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-06
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多