ryotatake blog

Webエンジニア

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のふるまいを考えて整理してみました。

こちらは必ずしも正しくないと思います。間違っていたらご指摘いただけますと幸いです。


  1. *がついている状態では、カンマ区切りの複数の値を持つものとして扱われる
  2. *が外れると配列になる
  3. *がついている状態でも、*のついていない変数に代入されると配列になる
  4. 逆に*のついている変数に代入すれば、カンマ区切りの状態は維持される


これを確かめるために、まずは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を扱うもののようです。また調べたいと思います。