Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is it better to use a Struct rather than a Hash in Ruby?

Tags:

ruby

A Ruby Struct allows an instance to be generated with a set of accessors:

# Create a structure named by its constant Customer = Struct.new(:name, :address)     #=> Customer Customer.new("Dave", "123 Main")           #=> #<Customer name="Dave", address="123 Main"> 

This looks convenient and powerful, however, a Hash does something pretty similar:

Customer = {:name => "Dave", :address => "123 Main"} 

What are the real-world situations where I should prefer a Struct (and why), and what are the caveats or pitfalls in choosing one over the other?

like image 831
Walt Jones Avatar asked May 01 '09 04:05

Walt Jones


People also ask

What is struct in Ruby?

Struct is a compact way to group together a number of attributes, using accessor methods, without creating an explicit class. The Struct class is a creator of specific classes, each one is defined to hold a set of variable and their accessors. The subclass of Struct class is Struct::Tms.

Is a Hash an object in Ruby?

In Ruby, Hash is a collection of unique keys and their values. Hash is like an Array, except the indexing is done with the help of arbitrary keys of any object type. In Hash, the order of returning keys and their value by various iterators is arbitrary and will generally not be in the insertion order.

What is hashing in Ruby?

Advertisements. A Hash is a collection of key-value pairs like this: "employee" = > "salary". It is similar to an Array, except that indexing is done via arbitrary keys of any object type, not an integer index.

Are hashes ordered in Ruby?

Hashes are not meant to be in a certain order (though they are in Ruby 1.9) as they're a data structure where one thing merely relates to another thing.


2 Answers

Personally I use a struct in cases when I want to make a piece of data act like a collection of data instead of loosely coupled under a Hash.

For instance I've made a script that downloads videos from Youtube and in there I've a struct to represent a Video and to test whether all data is in place:

 Video = Struct.new(:title, :video_id, :id) do   def to_s     "http://youtube.com/get_video.php?t=#{id}&video_id=#{video_id}&fmt=18"   end    def empty?     @title.nil? and @video_id.nil? and @id.nil?   end end 

Later on in my code I've a loop that goes through all rows in the videos source HTML-page until empty? doesn't return true.

Another example I've seen is James Edward Gray IIs configuration class which uses OpenStruct to easily add configuration variables loaded from an external file:

#!/usr/bin/env ruby -wKU  require "ostruct"  module Config   module_function    def load_config_file(path)     eval <<-END_CONFIG     config = OpenStruct.new     #{File.read(path)}     config     END_CONFIG   end end  # configuration_file.rb config.db = File.join(ENV['HOME'], '.cool-program.db') config.user = ENV['USER']  # Usage: Config = Config.load_config('configuration_file.rb') Config.db   # => /home/ba/.cool-program.db Config.user # => ba Config.non_existant # => Nil 

The difference between Struct and OpenStruct is that Struct only responds to the attributes that you've set, OpenStruct responds to any attribute set - but those with no value set will return Nil

like image 152
gaqzi Avatar answered Oct 19 '22 22:10

gaqzi


A Struct has the feature that you can get at its elements by index as well as by name:

irb(main):004:0> Person = Struct.new(:name, :age) => Person irb(main):005:0> p = Person.new("fred", 26) => # irb(main):006:0> p[0] => "fred" irb(main):007:0> p[1] => 26 irb(main):008:0> p.name => "fred" irb(main):009:0> p.age => 26

which sometimes is useful.

like image 25
JDonner Avatar answered Oct 20 '22 00:10

JDonner