рубин клонировать объект - PullRequest
0 голосов
/ 13 октября 2018

Мне нужно клонировать существующий объект и изменить этот клонированный объект.Проблема в том, что мои изменения меняют исходный объект.Вот код:

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

Есть ли способ это исправить?

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

Вам даже не нужно клонировать здесь, вам просто нужно создать новый экземпляр.

Прямо здесь:

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

у вас нет двух экземпляров Http,у тебя есть.У вас просто есть две переменные, указывающие на один и тот же экземпляр.

Вместо этого вы можете изменить его на это, и у вас не возникнет проблема.

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

Если, однако, вы использовалиАргумент options shared, вот где вы можете столкнуться с проблемой:

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
0 голосов
/ 13 октября 2018

Вы хотите .clone или, возможно, .dup

test2 = test.clone

Но в зависимости от ваших целей, но в этом случае вы, вероятно, захотите .clone см. В чем разница между дуплом Руби иметоды клонирования?

Основное отличие состоит в том, что .clone также копирует объекты синглтон-методов и замороженное состояние.

В примечании можно также изменить

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