Reputation: 1349
They can be defined like this
Struct.new(:x, :y)
But what can usefully be done with them? Specifically, how can I create an instance of such a struct? This doesn't work
Struct.new(:x => 1, :y => 1)
(you get TypeError: can't convert Hash into String
).
I'm using Ruby 1.9.2.
UPDATE:
Good pointers so far, thanks. I suppose the reason I asked this was that I have several times found myself wanting to do this
Struct.new(:x => 1, :y => 1)
just so that I can pass an object around where I can write obj.x
instead of, say, instantiating a hash and having to write obj[:x]
. In this case I want the structure to be really anonymous - I don't want to pollute my namespace with anything by naming what is returned from the Struct.new
call. The closest thing to that, as already suggested is
Struct.new(:x, :y).new(1, 1)
But how do you like them apples? I'm not sure I do. Is it reasonable to expect to be able to define and instantiate an anonymous struct in one go (as part of core Ruby)? I guess when I read the official Ruby docs on Struct.new
I assume the word 'anonymous' allows this, but it doesn't.
Upvotes: 7
Views: 5244
Reputation: 4810
OpenStruct
is probably what you want, but I ran into a situation recently where OpenStruct
didn't work because I needed to raise an error when trying to access an undefined attribute. Struct
does this:
os = OpenStruct.new
os.x = 1; os.y = 2;
os.z # returns nil
s = Struct.new(:x, :y).new
s.x = 1; s.y = 2;
s.z # raises NoMethodError
Just something to keep in mind.
Upvotes: 1
Reputation: 9110
Well, you can use Structs when you don't actually want to write a class with accessors. It's handy to just write
Project = Struct.new(:name)
instead of
class Project
attr_accesor :name
end
As tokland pointed out correctly (thanks!), a Struct also gives you a nice #initialize method automagically. So the following is possible without any further code:
Project = Struct.new(:name)
p = Project.new('Quadriloptic Curves')
Upvotes: 4
Reputation: 4072
Struct.new
returns a Class
, so you can, for example, assign it to a constant like this:
Point = Struct.new(:x, :y)
or subclass it:
class Point < Struct.new(:x, :y)
# custom methods here
# ...
end
In both cases, you can use the resulting class like this:
Point.new(3, 5)
If you don't want to create a specific class (because you need to instantiate an object of that class only once), consider to use OpenStruct
instead:
require 'ostruct'
point = OpenStruct.new(:x => 3, :y => 5)
Upvotes: 19
Reputation: 508
As for creating instances:
User = Struct.new(:user,:password)
u = User.new("john","secret")
Upvotes: 0
Reputation: 3472
You first create a struct, and then you can create instances of it. It's a way of creating data objects without having to declare a class. Basically it's the same as a hash, but it's more clean to access the objects. You can get stuff out of it by referencing it via ordinary accessor methods.
http://www.ruby-doc.org/core-1.9.3/Struct.html
# Create a structure with a name in Struct
Struct.new("Customer", :name, :address) #=> Struct::Customer
Struct::Customer.new("Dave", "123 Main") #=> #<struct Struct::Customer name="Dave", address="123 Main">
# Create a structure named by its constant
Customer = Struct.new(:name, :address) #=> Customer
Customer.new("Dave", "123 Main") #=> #<struct Customer name="Dave", address="123 Main">
Upvotes: 5
Reputation: 8408
I'm hot sure about purpose but Struct.new
returns class so
irb(main):001:0> Struct.new(:x,:y)
=> #<Class:0x2914110>
irb(main):002:0> Struct.new(:x,:y).new(1,2)
=> #<struct x=1, y=2>
Upvotes: 3