tags:

views:

70

answers:

2

I don't have much programming experience. But to me, Struct seems somewhat similar to Hash.

  • What tasks does Struct do very good?
  • Is there anything Struct can do, but Hash cannot do?

After googling, the concept of Struct is important in C, but I don't know much about C.

+2  A: 

From the Struct documentation:

A Struct is a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class.

On the other hand, a Hash:

A Hash is a collection of key-value pairs. It is similar to an Array, except that indexing is done via arbitrary keys of any object type, not an integer index. The order in which you traverse a hash by either key or value may seem arbitrary, and will generally not be in the insertion order.

The main difference is how you access your data.

ruby-1.9.1-p378 > Point = Struct.new(:x, :y)
 => Point 
ruby-1.9.1-p378 > p = Point.new(4,5)
 => #<struct Point x=4, y=5> 
ruby-1.9.1-p378 > p.x
 => 4 
ruby-1.9.1-p378 > p.y
 => 5 
ruby-1.9.1-p378 > p = {:x => 4, :y => 5}
 => {:x=>4, :y=>5} 
ruby-1.9.1-p378 > p.x
NoMethodError: undefined method `x' for {:x=>4, :y=>5}:Hash
    from (irb):7
    from /Users/mr/.rvm/rubies/ruby-1.9.1-p378/bin/irb:17:in `<main>'
ruby-1.9.1-p378 > p[:x]
 => 4 
ruby-1.9.1-p378 > p[:y]
 => 5 

In short, you would make a new Struct when you want a class that's a "plain old data" structure (optionally with the intent of extending it with more methods), and you would use a Hash when you don't need a formal type at all.

Mark Rushakoff
+8  A: 

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.
  • If you don't know the name of the attribute you want to access until runtime, you need to use send to access the attribute, while with a hash not knowing the key until runtime makes no difference at all.
  • Relatedly 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, whereas Foo = Struct.new(:x); Foo.new(42)==Foo.new(42) is true).
  • The to_a method for structs returns an array of values, while to_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 do Foo.new(1,2,3) to create an instance of Foo 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.

sepp2k
Your other points are all correct (so +1 for that), but [`Struct#==`](http://ruby-doc.org/core/classes/Struct.html#M000890) works differently from what you explained when you actually store the result of `Struct.new` as opposed to calling it twice with the same arguments.
Mark Rushakoff
@MarkRushakoff: If I do `Foo = Struct.new(:x); Bar = Struct.new(:x)` and then do `Foo.new(42) == Bar.new(42)` I will get false. If I do `Foo.new(42) == Foo.new(42)` I will get true. And if you read carefully, that's exactly what I said (Two instances of *different* structs").
sepp2k
I see what you mean. It wasn't clear to me because you didn't contrast it with an explanation that equality works as expected when using the same Struct type.
Mark Rushakoff
@Mark: Ok, I edited to add that.
sepp2k