End of Life Ruby 3.2 has reached end of life and gets no more fixes. Switch to Ruby 4.0 →
Struct.new
static VALUE
rb_struct_s_def(int argc, VALUE *argv, VALUE klass)
{
VALUE name, rest, keyword_init = Qnil;
long i;
VALUE st;
st_table *tbl;
VALUE opt;
argc = rb_scan_args(argc, argv, "1*:", NULL, NULL, &opt);
name = argv[0];
if (SYMBOL_P(name)) {
name = Qnil;
}
else {
--argc;
++argv;
}
if (!NIL_P(opt)) {
static ID keyword_ids[1];
if (!keyword_ids[0]) {
keyword_ids[0] = rb_intern("keyword_init");
}
rb_get_kwargs(opt, keyword_ids, 0, 1, &keyword_init);
if (UNDEF_P(keyword_init)) {
keyword_init = Qnil;
}
else if (RTEST(keyword_init)) {
keyword_init = Qtrue;
}
}
rest = rb_ident_hash_new();
RBASIC_CLEAR_CLASS(rest);
OBJ_WB_UNPROTECT(rest);
tbl = RHASH_TBL_RAW(rest);
for (i=0; i<argc; i++) {
VALUE mem = rb_to_symbol(argv[i]);
if (rb_is_attrset_sym(mem)) {
rb_raise(rb_eArgError, "invalid struct member: %"PRIsVALUE, mem);
}
if (st_insert(tbl, mem, Qtrue)) {
rb_raise(rb_eArgError, "duplicate member: %"PRIsVALUE, mem);
}
}
rest = rb_hash_keys(rest);
st_clear(tbl);
RBASIC_CLEAR_CLASS(rest);
OBJ_FREEZE_RAW(rest);
if (NIL_P(name)) {
st = anonymous_struct(klass);
}
else {
st = new_struct(name, klass);
}
setup_struct(st, rest);
rb_ivar_set(st, id_keyword_init, keyword_init);
if (rb_block_given_p()) {
rb_mod_module_eval(0, 0, st);
}
return st;
}
Struct.new returns a new subclass of Struct. The new subclass:
-
May be anonymous, or may have the name given by
class_name. -
May have members as given by
member_names. -
May have initialization via ordinary arguments, or via keyword arguments
The new subclass has its own method ::new; thus:
Foo = Struct.new('Foo', :foo, :bar) # => Struct::Foo f = Foo.new(0, 1) # => #<struct Struct::Foo foo=0, bar=1>
Class Name
With string argument class_name, returns a new subclass of Struct named Struct::<em>class_name</em>:
Foo = Struct.new('Foo', :foo, :bar) # => Struct::Foo Foo.name # => "Struct::Foo" Foo.superclass # => Struct
Without string argument class_name, returns a new anonymous subclass of Struct:
Struct.new(:foo, :bar).name # => nil
Block
With a block given, the created subclass is yielded to the block:
Customer = Struct.new('Customer', :name, :address) do |new_class| p "The new subclass is #{new_class}" def greeting "Hello #{name} at #{address}" end end # => Struct::Customer dave = Customer.new('Dave', '123 Main') dave # => #<struct Struct::Customer name="Dave", address="123 Main"> dave.greeting # => "Hello Dave at 123 Main"
Output, from Struct.new:
"The new subclass is Struct::Customer"
Member Names
Symbol arguments member_names determines the members of the new subclass:
Struct.new(:foo, :bar).members # => [:foo, :bar] Struct.new('Foo', :foo, :bar).members # => [:foo, :bar]
The new subclass has instance methods corresponding to member_names:
Foo = Struct.new('Foo', :foo, :bar) Foo.instance_methods(false) # => [:foo, :bar, :foo=, :bar=] f = Foo.new # => #<struct Struct::Foo foo=nil, bar=nil> f.foo # => nil f.foo = 0 # => 0 f.bar # => nil f.bar = 1 # => 1 f # => #<struct Struct::Foo foo=0, bar=1>
Singleton Methods
A subclass returned by Struct.new has these singleton methods:
-
Method
::newcreates an instance of the subclass:ExampleFoo.new # => #<struct Struct::Foo foo=nil, bar=nil> Foo.new(0) # => #<struct Struct::Foo foo=0, bar=nil> Foo.new(0, 1) # => #<struct Struct::Foo foo=0, bar=1> Foo.new(0, 1, 2) # Raises ArgumentError: struct size differs # Initialization with keyword arguments: Foo.new(foo: 0) # => #<struct Struct::Foo foo=0, bar=nil> Foo.new(foo: 0, bar: 1) # => #<struct Struct::Foo foo=0, bar=1> Foo.new(foo: 0, bar: 1, baz: 2) # Raises ArgumentError: unknown keywords: baz
Method
::[]is an alias for method::new. -
Method
:inspectreturns a string representation of the subclass:ExampleFoo.inspect # => "Struct::Foo"
-
Method
::membersreturns an array of the member names:ExampleFoo.members # => [:foo, :bar]
Keyword Argument
By default, the arguments for initializing an instance of the new subclass can be both positional and keyword arguments.
Optional keyword argument keyword_init: allows to force only one type of arguments to be accepted:
KeywordsOnly = Struct.new(:foo, :bar, keyword_init: true) KeywordsOnly.new(bar: 1, foo: 0) # => #<struct KeywordsOnly foo=0, bar=1> KeywordsOnly.new(0, 1) # Raises ArgumentError: wrong number of arguments PositionalOnly = Struct.new(:foo, :bar, keyword_init: false) PositionalOnly.new(0, 1) # => #<struct PositionalOnly foo=0, bar=1> PositionalOnly.new(bar: 1, foo: 0) # => #<struct PositionalOnly foo={:foo=>1, :bar=>2}, bar=nil> # Note that no error is raised, but arguments treated as one hash value # Same as not providing keyword_init: Any = Struct.new(:foo, :bar, keyword_init: nil) Any.new(foo: 1, bar: 2) # => #<struct Any foo=1, bar=2> Any.new(1, 2) # => #<struct Any foo=1, bar=2>
Ruby version changes
-
3.2
-
A
Structclass can also be initialized with keyword arguments withoutkeyword_init: trueonStruct.new[Feature #16806]ExamplePost = Struct.new(:id, :name) Post.new(1, "hello") #=> #<struct Post id=1, name="hello"> # From Ruby 3.2, the following code also works without keyword_init: true. Post.new(id: 1, name: "hello") #=> #<struct Post id=1, name="hello">
-