はじめに

この記事は書籍「プロを目指す人のためのRuby入門」に掲載できなかったトピックを著者自らが紹介するアドベントカレンダーの2日目です。
本文に出てくる章番号や項番号は書籍の中で使われている番号です。

今回はメソッドの引数をアスタリスク1文字にするイディオムを紹介します。

必要な前提知識

「プロを目指す人のためのRuby入門」の第7章まで読み終わっていること。

メソッドの引数をアスタリスク1文字にするイディオム

4.4.7項でも説明したとおり、メソッド定義で引数の前に*を使うとその引数が可変長引数になります。

def greeting(*names)
  "#{names.join('と')}、こんにちは!"
end
greeting('田中さん')                       #=> "田中さん、こんにちは!"
greeting('田中さん', '鈴木さん')            #=> "田中さんと鈴木さん、こんにちは!"
greeting('田中さん', '鈴木さん', '佐藤さん') #=> "田中さんと鈴木さんと佐藤さん、こんにちは!"

可変長引数は次のように引数名を省略することもできます。

def greeting(*)
  # 中身はいったん空にする
end
greeting('田中さん')                       #=> nil
greeting('田中さん', '鈴木さん')            #=> nil
greeting('田中さん', '鈴木さん', '佐藤さん') #=> nil

さて、このままだと何もメリットがないように見えますが、以下のような条件が揃った場合にアスタリスク1文字だけの可変長引数が利用されることがあります。

  • サブクラスがsuperを使ってスーパークラスの同名メソッドを呼び出す
  • 渡された引数は全部そのままスーパークラスに渡す
  • サブクラスのメソッド内では引数を利用しない

たとえば次のようなコードです。

class Product
  attr_reader :name, :price

  def initialize(name, price)
    @name = name
    @price = price
  end
end

class DVD < Product
  # 明示的にname, priceという引数を書く代わりに、*だけで済ませる
  def initialize(*)
    # 渡された引数を全部そのままスーパークラスに渡す
    super

    # サブクラスで必要な初期化処理を書く
  end
end

dvd = DVD.new('A great movie', 1000)
dvd.name  #=> "A great movie"
dvd.price #=> 1000

サブクラス側の実装は可変長引数なのでいくつでも引数を渡せますが、スーパークラス側はそうではないため、結果的に引数の数は2個に制限されます。

DVD.new('A great movie', 1000, 'foo')
#=> ArgumentError: wrong number of arguments (given 3, expected 2)

superの使い方については「7.6.5 superでスーパークラスのメソッドを呼び出す」の項で説明したので、忘れた方はもう一度読み直してください。

少しトリッキーなので、初心者のうちはわざわざこのような書き方を真似する必要はありません。
ですが、gemのコードを読んでいると、ときどきアスタリスク1文字の引数が登場することがあるので、知っておくとコードリーディングの際に役立つ場合があります。

次回予告

次回はローカル変数の宣言と代入の関係について説明します。