When to use Struct instead of Hash in Ruby?
I don't have much programming experience. But, to me, Struct seems somewhat similar to Hash.
- What can Struct do well?
- Is there anything Struct can do, that Hash cannot do?
After googling, the concept of Struct is important in C, but I don't know much about C.
Structs differ from using hashmaps in the following ways (in addition to how the code looks):
- A struct has a fixed set of attributes, while you add new keys to a hash.
- Calling an attribute that does not exist on an instance of a struct will cause a NoMethodError, while getting the value for a non-existing key from a hash will just return nil.
- Two instances of different structs will never be equal even if the structs have the same attributes and the instances have the same values (i.e.
Struct.new(:x).new(42) == Struct.new(:x).new(42)
is false, whereasFoo = Struct.new(:x); Foo.new(42)==Foo.new(42)
is true). - The
to_a
method for structs returns an array of values, whileto_a
on a hash gets you an array of key-value-pairs (where "pair" means "two-element array") - If
Foo = Struct.new(:x, :y, :z)
you can doFoo.new(1,2,3)
to create an instance ofFoo
without having to spell out the attribute names.
So to answer the question: When you want to model objects with a known set of attributes, use structs. When you want to model arbitrary use hashmaps (e.g. counting how often each word occurs in a string or mapping nicknames to full names etc. are definitely not jobs for a struct, while modeling a person with a name, an age and an address would be a perfect fit for Person = Struct.new(name, age, address)
).
As a sidenote: C structs have little to nothing to do with ruby structs, so don't let yourself get confused by that.
I know this question was almost well-answered, but surprisingly nobody has talked about one of the biggest differences and the real benefits of Struct
. And I guess that's why somebody is still asking.
I understand the differences, but what's the real advantage to using a Struct over a Hash, when a Hash can do the same thing, and is simpler to deal with? Seems like Structs are kind of superfluous.
Struct
is faster.
require 'benchmark'
Benchmark.bm 10 do |bench|
bench.report "Hash: " do
50_000_000.times do { name: "John Smith", age: 45 } end
end
bench.report "Struct: " do
klass = Struct.new(:name, :age)
50_000_000.times do klass.new("John Smith", 45) end
end
end
# ruby 2.2.2p95 (2015-04-13 revision 50295) [x64-mingw32].
# user system total real
# Hash: 22.340000 0.016000 22.356000 ( 24.260674)
# Struct: 12.979000 0.000000 12.979000 ( 14.095455)
# ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin11.0]
#
# user system total real
# Hash: 31.980000 0.060000 32.040000 ( 32.039914)
# Struct: 16.880000 0.010000 16.890000 ( 16.886061)
One more main difference is you can add behavior methods to a Struct.
Customer = Struct.new(:name, :address) do
def greeting; "Hello #{name}!" ; end
end
Customer.new("Dave", "123 Main").greeting # => "Hello Dave!"