问题
Hello I have a custom Hash that needs to be returned in an API. But currently I'm struggling to find a good way to do so. The following example will describe the problem.
Lets say we have the following code:
data = {name: "Jon", value: "13"}
results = []
[1, 2, 3, 4, 5].each do |i|
data[:id] = i
results << data
end
# output
# results = [{name: "Jon", value: "13", id: 5}, {name: "Jon", value: "13", id: 5}, {name: "Jon", value: "13", id: 5}, {name: "Jon", value: "13", id: 5}, {name: "Jon", value: "13", id: 5}]
I expected something like this:
# results = [{name: "Jon", value: "13", id: 1}, {name: "Jon", value: "13", id: 2}, {name: "Jon", value: "13", id: 3}, {name: "Jon", value: "13", id: 4}, {name: "Jon", value: "13", id: 5}]
How can I achieve this format efficiently (memory usage)? The following code fixes the reference issue (because it creates a new hash) but is inefficient, because my initial hash 'data' is really big.
# inefficient but working
[1, 2, 3, 4, 5].each do |i|
data[:id] = i
results << data.dup
end
# output
# results = [{name: "Jon", value: "13", id: 1}, {name: "Jon", value: "13", id: 2}, {name: "Jon", value: "13", id: 3}, {name: "Jon", value: "13", id: 4}, {name: "Jon", value: "13", id: 5}]
Thank you!
回答1:
You can't.
References in Ruby (and in almost every other programming language) point to a single object in memory.
irb(main):004:0> h = { foo: :bar }
=> {:foo=>:bar}
irb(main):005:0> h.object_id
=> 70125571572420
As long as I mutate h
I'm still working with same reference:
irb(main):006:0> h[:bar] = 'baz'
=> "baz"
irb(main):007:0> h.object_id
=> 70125571572420
If I want a slightly different version of h
without changing h
it will be stored as a separate object of course:
h.merge(x: 2).object_id
=> 70125567041320
.merge
in this case duplicates the hash and returns the result of merging it with args.
There is no way around this. Hashes in Ruby cannot "inherit" from a reference.
来源:https://stackoverflow.com/questions/46330186/ruby-hash-key-reference