コンテンツにスキップ

スプラット展開とタプル

メソッドはスプラット展開 (*) を使うことで複数の引数を一度に受け取ることができます。これは仮引数の中で1回だけしか指定できませんが、順序を問わずにどの場所にでも指定可能です。

def sum(*elements)
  total = 0
  elements.each do |value|
    total += value
  end
  total
end

sum 1, 2, 3      # => 6
sum 1, 2, 3, 4.5 # => 10.5

渡された引数はメソッドの中で Tuple として扱うことができます。

# elements は Tuple(Int32, Int32, Int32) になる
sum 1, 2, 3

# elements は Tuple(Int32, Int32, Int32, Float64) になる
sum 1, 2, 3, 4.5

仮引数でスプラット指定された引数のあとの引数は、名前付き引数としてのみ渡すことができます。

def sum(*elements, initial = 0)
  total = initial
  elements.each do |value|
    total += value
  end
  total
end

sum 1, 2, 3              # => 6
sum 1, 2, 3, initial: 10 # => 16

スプラット指定された引数のあとの引数でデフォルト値が無い場合は、名前付き引数として渡さなければいけない引数となります。

def sum(*elements, initial)
  total = initial
  elements.each do |value|
    total += value
  end
  total
end

sum 1, 2, 3              # Error, missing argument: initial
sum 1, 2, 3, initial: 10 # => 16

2つの引数の名前のみが違うメソッドはおたがいにオーバーロードされています。

def foo(*elements, x)
  1
end

def foo(*elements, y)
  2
end

foo x: "something" # => 1
foo y: "something" # => 2

スプラット指定された引数は名前をつけないこともできて、その場合はそれ以降の引数は「名前付き引数として渡さなければいけない」ということになります。

def foo(x, y, *, z)
end

foo 1, 2, 3    # Error, wrong number of arguments (given 3, expected 2)
foo 1, 2       # Error, missing argument: z
foo 1, 2, z: 3 # OK

タプルのスプラット展開

タプル はメソッド呼び出しで * を使うことで引数に展開されて渡されます。

def foo(x, y)
  x + y
end

tuple = {1, 2}
foo *tuple # => 3

二重スプラット展開と名前付きタプル

二重スプラット展開 (**) はその他の引数にマッチしなかったすべての名前付き引数をキャプチャします。この引数の型は NamedTuple となります。

def foo(x, **other)
  # NamedTuple としてキャプチャした名前付き引数を返す
  other
end

foo 1, y: 2, z: 3    # => {y: 2, z: 3}
foo y: 2, x: 1, z: 3 # => {y: 2, z: 3}

名前付きタプルの二重スプラット

NamedTuple はメソッド呼び出しで ** を使うことで引数に展開されて渡されます。

def foo(x, y)
  x - y
end

tuple = {y: 3, x: 10}
foo **tuple # => 7