ナスカブログ

未来の自分へのドキュメント

Ruby 引数について理解する

引数について理解しないとな〜と思いつつ時が流れようやく思い腰を上げる

rubyリファレンスに以下とある

メソッド定義において、仮引数はその種類毎に以下の順序でしか指定することはできません。いずれも省略することは可能です。

  • デフォルト式のない引数(複数指定可)
  • デフォルト式のある引数(複数指定可)
  • *を伴う引数(1つだけ指定可)
  • デフォルト式のない引数(複数指定可)
  • キーワード引数(複数指定可)
  • ** を伴う引数(1つだけ指定可)
  • & を伴う引数(1つだけ指定可)

クラス/メソッドの定義 (Ruby 2.7.0 リファレンスマニュアル)

実引数と仮引数

  • メソッドを定義する時にどのような値を受け取るかはわからないため仮に置いておくということでメソッド定義時の引数は仮引数という
  • 実際にメソッドを呼び出すときは値がわかっているのでその引数を実引数という

定義方法は以下

def メソッド名(仮引数)
  ## 処理 ##
end

メソッド名(実引数)

デフォルト式のない引数(複数指定可)

def hoge(arg)
  arg
end

p hoge('aaa') #=> "aaa"
  • 複数指定
def hoge(arg1, arg2)
  p arg1 #=> "aaa"
  p arg2  #=> "bbb"
end

hoge('aaa', 'bbb')

デフォルト式のある引数(複数指定可)

def hoge(arg = 'fuga')
  arg
end

p hoge(arg1 = 'aaa') #=> "aaa"
  • 複数指定
def hoge(arg1 = 'fuga1', arg2 = 'fuga2')
  [arg1, arg2]
end

p hoge(arg3 = 'aaa', arg4 = 'bbb') #=> ["aaa", "bbb"]
  • 実引数省略
def hoge(arg1 = 'fuga1')
  arg1
end

p hoge #=> "fuga1"

*を伴う引数(1つだけ指定可)

  • *をつけると配列として格納される
def hoge(*arg)
  p arg.class #=> Array
  arg
end

p hoge('aaa', 'bbb') #=> ["aaa", "bbb"]

メソッドの中で*をつける時は注意が必要

def hoge(*arg)
  p *arg
end

hoge('aaa', 'bbb')
#=> "aaa"
#=> "bbb"
def hoge(*arg)
  *arg
end

p hoge('aaa', 'bbb') #=> syntax error, unexpected '\n', expecting '='

デフォルト式のない引数(複数指定可) 2回目

*引数は最後のあまりものをまとめて配列にしてくれるっぽい

def hoge(arg1, *arg2, arg3, arg4)
  [arg1, arg2, arg3, arg4]
end

p hoge('aaa', 'bbb', 'ccc', 'ddd') #=> ["aaa", ["bbb"], "ccc", "ddd"]

*引数を2つ以上記述するとエラーが出る

def hoge(arg1, *arg2, *arg3, arg4)
  [arg1, arg2, arg3, arg4]
end

p hoge('aaa', 'bbb', 'ccc', 'ddd') #=> syntax error, unexpected *

キーワード引数(複数指定可)

  • key: valueの形で渡す
def hoge(arg1: 'fuga1')
  arg1
end

p hoge(arg1: '#fuga') #=> "#fuga"
  • 仮引数と実引数のkeyは一致しないとエラー
def hoge(arg1: 'fuga1')
  arg1
end

p hoge(arg: '#fuga') #=> unknown keyword: :arg (ArgumentError)
  • 複数指定
def hoge(arg1: 'fuga1', arg2: 'fuga2')
  [arg1, arg2]
end

p hoge(arg1: 'aaa', arg2: 'bbb') #=> ["aaa", "bbb"]
  • 実引数省略
def hoge(arg1: 'fuga1', arg2: 'fuga2')
  [arg1, arg2]
end

p hoge(arg1: 'aaa') #=> ["aaa", "fuga2"]

** を伴う引数(1つだけ指定可)

  • **をつけるとハッシュとして格納される
  • ハッシュなのでキーとバリューの形で引数を渡す必要がある
def hoge(**arg)
  p arg.class #=> Hash
  arg
end

p hoge(arg1: 'aaa', arg2: 'bbb') #=> {:arg1=>"aaa", :arg2=>"bbb"}

これもメソッドの中で**をつけて呼び出す時に注意が必要

def hoge(**arg)
  p **arg
end

hoge(arg1: 'aaa', arg2: 'bbb') #=> {:arg1=>"aaa", :arg2=>"bbb"}
def hoge(**arg)
  **arg
end

p hoge(arg1: 'aaa', arg2: 'bbb') #=> syntax error, unexpected **arg
  • **引数を2つ以上記述するとエラーが出る
def hoge(**arg1, **arg2)
  [arg1, arg2]
end

p hoge(arg1: 'aaa', arg2: 'bbb') #=> syntax error, unexpected **arg, expecting & or '&'

& を伴う引数(1つだけ指定可)

  • ブロックの中身はblock.callまたはyieldで実行される
def hoge(&arg)
  arg.call
end

hoge { p 'aaa' } #=> "aaa"
def hoge(&arg)
  yield
end

hoge { p 'aaa' } #=> "aaa"
  • &引数を2つ以上記述するとエラーが出る
def hoge(&arg, &arg2)
  [arg.call, arg2.call
end

hoge { p 'aaa' }, { p 'bbb' } #=> syntax error, unexpected ',', expecting ')'

最後に全ての書き方を詰め込むと以下のように記述できる(褒められたものではない)

def hoge(arg, arg2, arg3 = 'hoge1', arg4 = 'hoge2', *arg5, arg6, arg7, arg8: 'fuga1', arg9: 'fuga2', **arg10, &arg11)
  [arg, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11.call]
end

p hoge('aaa', 'bbb', arg3 = 'ccc', arg4 ='ddd', ['eee', 'fff'], 'ggg', 'hhh', arg8: 'iii', arg9: 'jjj', piyo: 'kkk') { p 'lll' }
#=> ["aaa", "bbb", "ccc", "ddd", [["eee", "fff"]], "ggg", "hhh", "iii", "jjj", {:piyo=>"kkk"}, "lll"]

複数指定できるものは2回ずつ引数を書いている

引数はそれぞれ以下のように対応している

引数 種類
arg, arg2 デフォルト式のない引数(複数指定可)
arg3, arg4 デフォルト式のある引数(複数指定可)
arg5 *を伴う引数(1つだけ指定可)
arg6, arg7 デフォルト式のない引数(複数指定可)
arg8, arg9 キーワード引数(複数指定可)
arg10 ** を伴う引数(1つだけ指定可)
arg11 & を伴う引数(1つだけ指定可)

まとめ

  • *が1つだけの引数は配列、2つの引数はハッシュとして扱う
  • *引数は可変長引数, **引数はオプション引数
  • *引数の後にはデフォルト式のない引数をもう一度書くことができる