Rubyでは引数を指定する際に*を付けることで引数展開ができます。
def foo(arg1,arg2,arg3) p arg1 p arg2 p arg3 end ary = [1,2,3] foo(*ary)
1 2 3
同様に、ハッシュやRangeオブジェクトも引数展開できます。
def foo(arg1,arg2,arg3) p arg1 p arg2 p arg3 end hash = {a:1,b:2,c:3} range = 1..3 foo(*hash) foo(*range)
[:a, 1] [:b, 2] [:c, 3] 1 2 3
では、String型で引数展開するとどうなるでしょう?
def foo(arg1,arg2,arg3) p arg1 p arg2 p arg3 end str = "str" foo(*str)
test.rb:1:in `foo': wrong number of arguments (given 1, expected 3) (ArgumentError) from test.rb:9:in `<main>'
出来ませんでした!
*を使った引数展開は内部的にto_a
メソッドを呼び出しているので、to_a
の無いクラスでは使えません。
メソッド呼び出し(super・ブロック付き・yield) (Ruby 3.3 リファレンスマニュアル)
ということで、Stringクラスにto_a
を追加してみます。
def foo(arg1,arg2,arg3) p arg1 p arg2 p arg3 end class String def to_a self.chars end end str = "str" foo(*str)
"s" "t" "r"
今度は出来ました!
同様にto_a
メソッドを実装すれば他のクラスでも*を使った引数展開ができるようになります。
# Integerクラスで引数展開する def foo(arg1,arg2,arg3) p arg1 p arg2 p arg3 end class Integer def to_a self.digits.reverse end end int = 123 foo(*int)
1 2 3
まとめ
既存のクラスでもオープンクラスを使ってto_a
を追加することで引数展開できるようになります!
とはいえモンキーパッチのご利用は計画的に~。