Ruby:Splat Operatorの挙動について調べてみた。
チェリー本を読んでいて、Rubyでよく見かける*argsの*はSplat Operatorと呼ぶことを知りました。
ただ挙動が中々理解できなかったので、調べてみました。
Splat Operatorとは
def method(*args) ... end
のように使われている、*のことをSplat Operatorと呼びます。
まずはSplat Operatorでできること
配列に変換
配列に変換することができます。
string = *"string" p string #=> ["string"] symbol = *:symbol p symbol #=> [:symbol] range = *(1..10) p range #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ただし、変数に代入しないと違う結果になります。
p *"string" #=> "string" p *:symbol #=> :symbol p *(1..10) #=> 1 #=> 2 #=> 3 #=> 4 #=> 5 #=> 6 #=> 7 #=> 8 #=> 9 #=> 10
配列を展開
配列を展開することができます(splat展開とも呼ばれるようです)。
a = [1, 2, 3] b = [4, 5, *a, 6] p b #=> [4, 5, 1, 2, 3, 6] p *a #配列が展開されるので、`p 1, 2, 3`と同じ結果になる。 #=> 1 #=> 2 #=> 3
可変長引数を取る
メソッドを定義する際に、可変長引数を取れるようにするために使われます。
def method(foo, bar, *baz) p foo p bar p "----" p *baz end method(1, 2, 3) #=> 1 #=> 2 #=> "----" #=> 3 method(1, 2, 3, 4) #=> 1 #=> 2 #=> "----" #=> 3 #=> 4
可変長引数は、メソッド内でどのように呼び出すかによって挙動が変わります。
def method(*args) p args #配列が返る p "----" p *args #配列にはならない end method(1, 2) #=> [1, 2] #=> "----" #=> 1 #=> 2
Splat Operatorが何をしているのか考える
どうして上のようにできるのか、Splat Operatorのふるまいを考えて整理してみました。
こちらは必ずしも正しくないと思います。間違っていたらご指摘いただけますと幸いです。
*がついている状態では、カンマ区切りの複数の値を持つものとして扱われる*が外れると配列になる*がついている状態でも、*のついていない変数に代入されると配列になる- 逆に
*のついている変数に代入すれば、カンマ区切りの状態は維持される
これを確かめるために、まずはpメソッドで調べてみます。
*がついているときは、p 1, 2と同様に扱われ(カンマ区切りが維持され)、*が外れると配列として扱われていることが分かります。
また、*がついている変数を*がついていない変数に代入すると配列になり、*がついている変数に代入するとカンマ区切りが維持されています。
*a = 1, 2 p *a # `p 1, 2` として扱われる #=> 1 #=> 2 p a # 配列として扱われる #=> [1, 2] b = *a # 配列として扱われる p b #=> [1, 2] *b = *a # *aの状態が維持される p *b #=> 1 #=> 2
次にclassメソッドで調べてみます。
*がつくとSyntaxErrorとなってしまうので、クラスには属さないようです。*が外れるとArrayクラスであることが分かります。
*a = 1, 2 *a.class #=> SyntaxError: (irb):53: syntax error, unexpected '\n', expecting '=' a.class #=> Array
おわりに
まとめてみて、Splat Operatorについては少し分かったような気がします。
今後実践で使っていく中で使い方に慣れていきたいです。
また、Ruby2.0以降からはdouble splat **が導入されていて、こちらはHashを扱うもののようです。また調べたいと思います。