What is a Struct in Ruby?
Let’s say that you need to store related data together but you don’t need methods & you don’t want to create a class…
A Ruby Struct solves this problem by letting you create objects with very simple syntax.
Point with two coordinates (
You wouldn’t want to create a whole class just to store these values together!
In this post:
You’ll learn how to create structs, the difference between a Ruby Struct & OpenStruct, and a few things you should watch out for!
You can create a
Struct by calling
new & passing in a list of symbols that’ll become the instance variables of this class.
They will have accessors defined by default, both for reading & writing.
Here’s an example:
person = Struct.new(:name, :age, :gender)
Now you can create an object like this:
john = person.new "john", 30, "M" puts john.age puts john.class
A good thing about structs if that you can compare them directly, based on their attributes:
john == john # true
If this was a regular Ruby object you would have to define the
== method yourself.
This is what we call a “value object“.
There are some differences with a “normal” class that you should be aware of.
You may have noticed that the class of our
john object is just
If you want to give your struct a name…
You should use one of these:
# Option 1 - Assign to a constant Person = Struct.new(:name, :age, :gender) # Option 2 - Subclass class Person < Struct.new(:name, :age, :gender) end
Both of these options will make your new objects have the class name you want.
Which is good!
Option 1 is the most common.
Another caveat with struct-generated classes is that...
They won't enforce the correct number of arguments for the constructor!
Let me explain.
With a proper class you would see this error:
ArgumentError: wrong number of arguments (0 for 3)
But if you are using a
Struct the missing arguments will be nil:
Person.new("peter") # struct Person name="peter", age=nil, gender=nil
Keep this in mind when working with
Another weird thing:
Struct.new(:a).ancestors [#<Class:0x29b1040>, Struct, Enumerable, Object, Kernel, BasicObject]
Let's say that you're reading lines from a file & each line represents one item.
200 /login 18:00 404 /bacon 18:03 200 /books 18:04
You work more easily with this data if you create a custom class.
LogEntry = Struct.new(:status, :url, :time) LogEntry.new(200, '/books', '18:04')
But to make it extra clear what every argument represents you may want to use keyword arguments.
Ruby 2.5 added support for keywords arguments in
Here's how to use it:
LogEntry = Struct.new(:status, :url, :time, keyword_init: true) LogEntry.new(status: 200, url: '/books', time: '18:04')
Now you can parse your file & convert it into
If you just need a one-off object, then you should consider using
require 'ostruct' cat = OpenStruct.new(color: 'black') puts cat.class puts cat.color
Notice how you have to require
ostruct to have access to this class.
The difference between
OpenStruct is a fancy Hash object, while a
Struct is like creating a new class from a template.
You've learned about Ruby Struct & OpenStruct! As long as you are aware of the special characteristics of each of these classes you'll be fine.
Now it's your turn to practice 🙂