13

Ruby version: 2.3.1

It does not appear that Ruby Structs can be declared using keyword params. Is there a way to do this within Struct?

Example:

MyStruct = Struct.new(:fname, :lname)
=> MyStruct

my_struct = MyStruct.new(fname: 'first', lname: 'last')
=> <struct MyStruct fname={:fname=>"first", :lname=>"last"}, lname=nil>

my_struct.fname
=> {:fname=>"first", :lname=>"last"}

my_struct.lname
=> nil
user3162553
  • 2,699
  • 3
  • 37
  • 61

2 Answers2

22

With Ruby 2.5, you can set the keyword_init option to true.

MyStruct = Struct.new(:fname, :lname, keyword_init: true)
# => MyStruct(keyword_init: true)
irb(main):002:0> my_struct = MyStruct.new(fname: 'first', lname: 'last')
# => #<struct MyStruct fname="first", lname="last">
Martinos
  • 2,116
  • 1
  • 21
  • 28
  • As of Ruby 3.2+, you no longer need to specify `keyword_init: true`. Structs can automatically be initialized by keyword arguments. https://www.ruby-lang.org/en/news/2022/12/25/ruby-3-2-0-released/ – Joshua Pinter May 11 '23 at 00:03
2
my_struct = MyStruct.new(fname: 'first', lname: 'last')

is the same as

my_struct = MyStruct.new({ fname: 'first', lname: 'last' })
  #=> #<struct MyStruct fname={:fname=>"first", :lname=>"last"}, lname=nil>

(one argument) so fname is set equal to the argument and lname is set to nil, in the same way that x, y = [2]; x #=> 2; y #=> nil.

This is because Ruby allows one to omit the braces when a hash is the argument of a method.

You may wish to search SO for related questions such as this one.

Community
  • 1
  • 1
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
  • Ok, that makes sense. However, I'm still not sure how to get the keyword arguments to work. I can pass in two hashes ie `MyStruct.new({fname: 'first'}, {lname: 'last'})` but that will give me a hash to work with rather than a string. – user3162553 Jan 12 '17 at 00:06
  • I seemed to have missed your 3-month-old comment. `my_struct = MyStruct.new({fname: 'first'}, {lname: 'last'}); my_struct.fname #=> {:fname=>"first"}; my_struct.lname #=> {:lname=>"last"}`. Does that answer your question? – Cary Swoveland Apr 21 '17 at 02:18
  • 1
    I wrote a gem (https://github.com/rohitpaulk/named_struct) that defines a `NamedStruct` class that inherits from Struct, and changes the initialization behavior to accept keyword arguments instead. – rohitpaulk Sep 27 '17 at 10:12