2
1

Rubyではメソッドの最後の引数がハッシュの場合、{}を省略できる

Last updated at Posted at 2024-08-01

はじめに

メソッドの引数に関するRuby特有の挙動がわからずハマったため、備忘録としてまとめます。

なおこの記事におけるRubyのバージョンは3.3です。

問題

以下のようなコードを見かけました。

class A
  attr_reader :arg1, :arg2, :arg3

  def initialize(arg1:, arg2:, arg3:)
    @arg1 = arg1
    @arg2 = arg2
    @arg3 = arg3
  end

  def execute
    # キーワード引数で3つの引数を渡しているつもり
    B.execute(param1: arg1, param2: arg2, param3: arg3)
  end
end


class B
  # 引数は1つだけ、キーワード引数でもない
  def self.execute(params)
    params.each do |key, value|
      puts "#{key}: #{value}"
    end
  end
end

a = A.new(arg1: 'a', arg2: 'b', arg3: 'c')
a.execute
#=> param1: a
#=> param2: b
#=> param3: c

AクラスのexecuteメソッドでBクラスのexecuteメソッドを呼び出しています。

メソッド呼び出し側ではキーワード引数で3つの引数を指定しているのに対し、Bクラス内のexecuteメソッドで指定されている引数はparams1つだけです。

キーワード引数にもなっていません。

こんな状態なのにも関わらず正常に動いていたため、疑問が湧きました。

解決策

Rubyではメソッドに引数を渡す際、最後の引数がハッシュであれば、波括弧{}を省略できます。

# メソッドの定義
def print_person_info(name, age, options = {})
  puts "名前: #{name}"
  puts "年齢: #{age}"
  options.each do |key, value|
    puts "#{key}: #{value}"
  end
end

# 通常のハッシュ表記
print_person_info("山田太郎", 30, {職業: "エンジニア", 趣味: "読書"})
#=> 名前: 山田太郎
#=> 年齢: 30
#=> 職業: エンジニア
#=> 趣味: 読書

# 最後の引数がハッシュの場合、波括弧を省略できる
print_person_info("佐藤花子", 25, 職業: "デザイナー", 趣味: "絵画")
#=> 名前: 佐藤花子
#=> 年齢: 25
#=> 職業: デザイナー
#=> 趣味: 絵画

冒頭のサンプルコードにもこの波括弧の省略が適用されています。

キーワード引数を3つ指定したつもりでしたが、実際には1つのハッシュとみなされていたのです。

つまり、次のように記述したのと同じ扱いになっていました。

class A
  attr_reader :arg1, :arg2, :arg3

  def initialize(arg1:, arg2:, arg3:)
    @arg1 = arg1
    @arg2 = arg2
    @arg3 = arg3
  end

  def execute
    # 3つの引数を渡しているように見えて、実際は1つのハッシュを渡している扱いとなる
    B.execute({ param1: arg1, param2: arg2, param3: arg3 })
  end
end


class B
  # 引数は1つだけ
  def self.execute(params)
    # ...
  end
end

これで謎が解けました。

おわりに

最後の引数がハッシュであれば省略可能なことは知っていたものの、3つの引数が1つのハッシュとみなされてるとは気づきませんでした。

Rubyの柔軟な挙動は良い時もある反面、コードリーディングをする際は苦しめられることもあるなと感じました。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1