Ruby Class vs Struct
To add to the other answers, there are some things you can not do with a Struct, and some than you can.
For example, you can not create a Struct with no arguments:
Bar = Struct.new
=> ArgumentError: wrong number of arguments (given 0, expected 1+)
Bar = Struct.new(:bar)
bar = Bar.new(nil)
bar.class
=> Bar
However, a class will let you do that:
class Foo; end
foo = Foo.new
foo.class
=> Foo
You can not set a default value for Struct arguments:
Bar = Struct.new(bar: 'default')
=> ArgumentError: unknown keyword: bar
Bar = Struct.new(bar = 'default')
=> NameError: identifier default needs to be constant
But you can do it with a class, either passing a hash, were the arguments can be in any order or even missing:
class Bar
attr_reader :bar, :rab
def initialize(bar: 'default', rab:)
@bar = bar
@rab = rab
end
end
bar = Bar.new(rab: 'mandatory')
bar.rab
=> 'mandatory'
bar.bar
=> 'default'
bar = Bar.new(rab: 'mandatory', bar: 'custom_value')
bar.rab
=> 'mandatory'
bar.bar
=> 'custom_value'
or passing the values directly, were the arguments should be given in the same order, with the defaulted ones always at the end:
class Bar
attr_reader :rab, :bar
def initialize(rab, bar = 'default')
@rab = rab
@bar = bar
end
end
bar = Bar.new('mandatory')
bar.rab
=> 'mandatory'
bar.bar
=> 'default'
bar = Bar.new('mandatory', 'custom_value')
bar.rab
=> 'mandatory'
bar.bar
=> 'custom_value'
You can not do any of that with Structs, unless you set default values for your arguments in this super verbose way:
A = Struct.new(:a, :b, :c) do
def initialize(a:, b: 2, c: 3)
super(a, b, c)
end
end
(example taken from this answer)
You can define methods in a Struct:
Foo = Struct.new(:foo) do
def method(argument)
# do something with argument
end
end
end
Structs can be useful to create data objects, like the point example mentioned in one of the answers.
I sometimes use them to create fakes and mocks in tests in a simple way. Sometimes RSpec allow(foo).to receive(:blah)
etc. can get a bit too verbose and using a Struct is much simple.
Struct is a Ruby shorthand for creating Classes. Using Struct where applicable simplifies your code. There is a good discussion of this at https://www.rubytapas.com/2012/11/07/episode-020-struct/
From the Struct docs:
A Struct is a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class.
The Struct class generates new subclasses that hold a set of members and their values. For each member a reader and writer method is created similar to Module#attr_accessor.
So, if I want a Person
class that I can access a name attribute (read and write), I either do it by declaring a class:
class Person
attr_accessor :name
def initalize(name)
@name = name
end
end
or using Struct:
Person = Struct.new(:name)
In both cases I can run the following code:
person = Person.new
person.name = "Name"
#or Person.new("Name")
puts person.name
When use it?
As the description states we use Structs when we need a group of accessible attributes without having to write an explicit class.
For example I want a point variable to hold X and Y values:
point = Struct.new(:x, :y).new(20,30)
point.x #=> 20
Some more examples:
- http://blog.steveklabnik.com/posts/2012-09-01-random-ruby-tricks--struct-new
- "When to use Struct instead of Hash in Ruby?" also has some very good points (comparing to the use of hash).