5.7K Views
April 06, 22
スライド概要
Ruby / Vim / C++
Ruby の引数の種類まとめ Shinjuku.rb #88 Online
自己紹介 名前:osyo Twitter : @pink_bangbi github : osyo-manga ブログ : Secret Garden(Instrumental) Rails エンジニア 好きな Ruby の機能は Refinements BuriKaigi2021 Ruby 2.0 から Ruby 3.0 を駆け足で振り返る BuriKaigi2022 Ruby のメタプログラミングで遊んでみよう RubyKaigi Takeout 2021 Use Macro all the time ~ マクロを使いまくろ ~
Ruby の引数の種類まとめ
諸注意 この記事は基本的に Ruby 3.1 を元にして動作確認しています 下にも書いてあるんですが `仮引数(parameter)` についての解説で `実引数(argument)` の話は あんまりでてきません 引数の名称は日本語に寄せていますが Ruby 界隈だと英語で書いてある事が多いかも 調べる時は英語の方で調べてもらったほうが情報はでてくると思う
引数という言葉の意味とは 『引数』という言葉には厳密に言うと『仮引数』と『実引数』という2つの意味がある 仮引数(parameter):メソッドを定義する時に使う変数名の事 実引数(argument):実際にメソッドに渡す(渡ってきた)値の事 メソッド定義時の a や b が仮引数(parameter) 1 2 3 # def plus(a, b) a + b 4 5 6 7 end 実際にメソッドを渡す値が実引数(argument) # plus(1, 2) このスライドでは『仮引数(parameter)』の種類について解説する 記述がない場合は『引数=仮引数(parameter)』と認識してください
Ruby の引数の種類
Ruby の引数の種類 Ruby の引数の種類には大きく分けで4つある
Ruby の引数の種類 Ruby の引数の種類には大きく分けで4つある 位置引数 (positional parameter)
Ruby の引数の種類 Ruby の引数の種類には大きく分けで4つある 位置引数 (positional parameter) キーワード引数 (keyword parameter)
Ruby の引数の種類 Ruby の引数の種類には大きく分けで4つある 位置引数 (positional parameter) キーワード引数 (keyword parameter) ブロック引数 (block parameter)
Ruby の引数の種類 Ruby の引数の種類には大きく分けで4つある 位置引数 (positional parameter) キーワード引数 (keyword parameter) ブロック引数 (block parameter) 転送引数 (forwarding parameter) この引数は Ruby 2.7 から追加された
ここから更に細かく分けると次のように分類される
ここから更に細かく分けると次のように分類される 位置引数 (positional parameter) 必須引数 (required parameter) オプショナル引数 (optional parameter) 残余引数 (rest parameter) 後置引数 (post-required parameter) 分割引数 (decomposed parameter)
ここから更に細かく分けると次のように分類される 位置引数 (positional parameter) 必須引数 (required parameter) オプショナル引数 (optional parameter) 残余引数 (rest parameter) 後置引数 (post-required parameter) 分割引数 (decomposed parameter) キーワード引数 (keyword parameter) 必須引数 (required parameter) オプショナル引数 (optional parameter) 残余引数 (rest parameter)
ここから更に細かく分けると次のように分類される 位置引数 (positional parameter) 必須引数 (required parameter) オプショナル引数 (optional parameter) 残余引数 (rest parameter) 後置引数 (post-required parameter) 分割引数 (decomposed parameter) キーワード引数 (keyword parameter) 必須引数 (required parameter) オプショナル引数 (optional parameter) 残余引数 (rest parameter) ブロック引数 (block parameter)
ここから更に細かく分けると次のように分類される 位置引数 (positional parameter) 必須引数 (required parameter) オプショナル引数 (optional parameter) 残余引数 (rest parameter) 後置引数 (post-required parameter) 分割引数 (decomposed parameter) キーワード引数 (keyword parameter) 必須引数 (required parameter) オプショナル引数 (optional parameter) 残余引数 (rest parameter) ブロック引数 (block parameter) 転送引数 (forwarding parameter)
また、引数を定義できる順番は基本的には以下のようになる 1 2 3 4 5 6 7 8 9 10 11 12 13 def test( 必須引数 (位置引数), オプショナル引数 (位置引数), 残余引数 (位置引数), 後置引数 (位置引数), 必須引数 (キーワード引数), オプショナル引数 (キーワード引数), 残余引数 (キーワード引数), ブロック引数 ) end 分割引数は上の順番に含まれない特殊な引数なので注意 また転送引数に関しても書き方が特殊なので別途記述する この記事ではこれらの引数について1つ1つ解説していく ちなみにこのスライドでは引数の名前を無理やり日本語に訳していますが Ruby 界隈だと英語読 みで話すことが多いかも…?
メソッドの引数情報を実行時に取得する メソッドの引数情報は Ruby の実行時に `Method#parameters` で取得する事ができる 1 2 3 4 5 def test(a, b = 1, *c, d, (e, f), g:, h: 2, **i, &j) end 6 7 8 # => [[:req, :a], # [:opt, :b], # [:rest, :c], 9 10 11 12 13 14 メソッドで オブジェクトを取得し、そこから parameters で引数情報を得る # method Method pp method(:test).parameters # # # # # # [:req, :d], [:req], [:keyreq, :g], [:key, :h], [:keyrest, :i], [:block, :j]]
記号 :req :opt :rest :keyreq :key :keyrest :block 意味 必須引数 (位置引数) や 後置引数 (位置引数) オプショナル引数 (位置引数) 残余引数 (位置引数) 必須引数 (キーワード引数) オプショナル引数 (キーワード引数) 残余引数 (キーワード引数) ブロック引数
ちなみに転送引数の場合は以下のような値が返ってくる 1 2 def test(...) end 3 4 5 pp method(:test).parameters # => [[:rest, :*], [:keyrest, :**], [:block, :&]] 参照:https://docs.ruby-lang.org/ja/latest/method/Method/i/parameters.html
位置引数 (positional parameter) メソッドに値を渡した順番に依存する形で値を受け取る引数 1つ目に渡した値は1つ目の引数で受け取る 位置引数には以下の定義方法がある 必須引数 (required parameter) オプショナル引数 (optional parameter) 残余引数 (rest parameter) 後置引数 (post-required parameter) 分割引数 (decomposed parameter) メソッドに値を渡す時に `*` を付けると配列が展開された状態で値が渡される
1 2 def test(a, b, c) { a: a, b: b, c: c } 3 4 5 6 end 7 8 pp test(*[1, 2, 3]) # => {:a=>1, :b=>2, :c=>3} 配列の中身を展開して位置引数に値を渡す と同じ意味 # # test(1, 2, 3)
必須引数 (required parameter) 必ず値を渡す必要がある位置引数 必ず つの値を受け取るメソッド 1 2 3 4 # 2 def plus(a, b) a + b end 5 6 7 8 # OK # pp plus(1, 2) メソッドの引数:a = 1, b = 2 # => 3 定義した必須引数の数と渡す値の数が一致していないとエラーになる 1 2 3 4 5 6 7 8 9 10 11 def plus(a, b) a + b end 必要な引数が足りなくてエラーになる # NG: # error: wrong number of arguments (given 1, expected 2) (ArgumentError) pp plus(1) 引数が多くてもエラーになる # NG: # error: wrong number of arguments (given 3, expected 2) (ArgumentError) pp plus(1, 2, 3)
オプショナル引数 (optional parameter) デフォルト値を設定して定義する位置引数 必須引数とは違いメソッドに値を渡さなくてもエラーにならない その場合はデフォルト値が変数に代入される 値を渡さなかった場合は になる 1 2 # pi = 3.14159 def circle_area(radius, pi = 3.14159) 3 4 5 6 radius * radius * pi end 7 8 9 10 11 12 値を渡すと pi = 2 となる # メソッドの引数:radius = 2, pi = 3 # pp circle_area(2, 3) 値を渡さなかった場合は メソッドの引数: # => 12 となる # pi = 3.14159 # radius = 2, pi = 3.14159 pp circle_area(2) # => 12.56636
デフォルト値は他のメソッドや他の引数を参照する事もできる 1 2 def pi 3.14 3 4 5 6 7 end @value = 42 引数 をデフォルト値として引数 を定義する # a b def test(a, b = a, c = pi, d = @value) 8 9 10 11 { a: a, b: b, c: c, d: d } end 12 # => {:a=>42, :b=>42, :c=>3.14, :d=>42} pp test(42)
またオプショナル引数を必須引数よりも後に書くと次のような挙動になる オプショナル引数ではなくて必須引数を優先して値を受け取る 引数が つの場合はオプショナル引数ではなくて必須引数で値を受け取る 1 2 3 4 # 1 def test(a = 1, b) { a: a, b: b } end 5 6 7 8 # 1 b = 5 pp test(5) # => {:a=>1, :b=>5} 9 10 11 12 引数が つの場合は 引数が つの場合は になる # 2 a = 6, b = 7 pp test(6, 7) # => {:a=>6, :b=>7} になる そして次のように必須引数の前後にオプショナル引数がある場合はエラーになるので注意する 1 2 3 # error: syntax error, unexpected '=', expecting ')' def test(a = 1, b, c = 2) end
残余引数 (rest parameter) 必須引数やオプショナル引数(や後述の後置引数)以外で渡された値を全て受け取る位置引数 渡された値は配列として受け取る `*` を付けて仮引数を定義する つ目以降に渡された値を全てを args で受け取る は渡された全ての値の配列になる 値がなければ空の配列になる 1 2 3 # 2 # args # 4 5 6 def sum(a, *args) return a + args.sum end 7 8 9 10 11 12 13 14 15 16 17 つ以上の任意の数の引数を渡すことができる # メソッドの引数:a = 1, args = [] # 1 p sum(1) # => 1 メソッドの引数:a = 1, args = [2] # p sum(1, 2) # => 3 メソッドの引数: # a = 1, args = [2, 3] p sum(1, 2, 3) # => 6
また残余引数は仮引数名を省略する事もできる 第一引数以外の位置引数は受け取らない 1 2 # def first(a, *) 3 4 5 6 7 a end pp first(1, 2, 3) # => 1
更に Ruby 3.2 からは変数名を省略した場合でも別のメソッドに引数を渡せるようになる予定 1 2 def foo(a, b, c) a + b + c 3 4 5 6 7 end 8 9 10 11 12 13 14 15 16 17 18 までは変数名を書いて他のメソッドに渡す必要があった で受け取った値をそのまま foo メソッドに渡す # Ruby 3.1 def hoge1(*args) # hoge1 foo(*args) end からは * だけで他のメソッドに渡すことができるようになった def hoge2(*) # hoge2 で受け取った値をそのまま foo メソッドに渡す # Ruby 3.2 foo(*) end pp hoge1(1, 2, 3) pp hoge2(1, 2, 3) # => 6 # => 6
後置引数 (post-required parameter) 残余引数以降に定義できる必須引数 残余引数と組み合わせて定義できる これを利用すると『残余引数の最後の値だけ』を受け取るようなこともできる 一番最後に渡された引数を last で受け取る 1 # 2 3 4 5 6 def last(*args, last) last end 7 8 9 10 11 12 13 14 複数の値を渡した中の最後の引数を返す # メソッドの引数:args = [1, 2, 3], last = 4 # pp last(1, 2, 3, 4) # => 4 実引数が つだけの場合は last で値を受け取る メソッドの引数:args = [], last = 42 # 1 # pp last(42) # => 42
必須引数と組み合わせる事もできる 前後の引数の値を受け取ることできる 1 2 # def first_last(first, *middle, last) 3 4 5 6 7 [first, last] end 8 # => [1, 4] メソッドの引数: # fisrt = 1, middle = [2, 3], last = 4 pp first_last(1, 2, 3, 4) また後置引数にはデフォルト値を設定する事はできない 1 2 3 # syntax error, unexpected '=', expecting ')' def test(*args, a = 1) end
分割引数 (decomposed parameter) 配列を分割して受け取る位置引数 分割引数は必須引数と後置引数の部分で記述できる `()` を付けて仮引数を定義する つ目の値を配列の要素を分割して受け取る 1 2 3 4 # 2 def test(a, (b, c)) { a: a, b: b, c: c } end 5 6 7 8 # [2, 3] b = 2, c = 3 pp test(1, [2, 3]) # => {:a=>1, :b=>2, :c=>3} を に分割して受け取る
分割引数は配列の要素数が定義した仮引数の数と違っていたり配列でなくても渡すことができる
1
2
def test(a, (b, c))
{ a: a, b: b, c: c }
3
4
5
6
7
end
8
9
10
11
12
13
14
15
16
17
18
19
配列の要素数が多くても渡すことができる
#
pp test(1, [2, 3, 4])
# => {:a=>1, :b=>2, :c=>3}
逆に少ない場合は
で埋められる
#
nil
pp test(1, [2])
# => {:a=>1, :b=>2, :c=>nil}
そもそも配列でなくても渡せる
#
pp test("hoge", "foo")
# => {:a=>"hoge", :b=>"foo", :c=>nil}
ただし、 つ以上の値を渡すとエラーになる
#
3
# error: `test': wrong number of arguments (given 3, expected 2) (ArgumentError)
pp test(1, 2, 3)
残余引数の受け取り方は多重代入と同じような挙動になる 詳細はこちら 配列の中身を分割して複数の変数に代入できる 1 2 3 4 # foo, bar, baz = [1, 2, 3] pp foo # => 1 pp bar # => 2 5 6 7 8 pp baz 9 10 11 12 13 14 15 16 # => 3 を付けると複数の値を配列で受け取る # * piyo, *post = [1, 2, 3] pp piyo pp post # => 1 # => [2, 3] 前後で分けて値を受け取る事もできる # first, *mid, pp first # pp mid # pp last # last = [1, 2, 3, 4, 5] => 1 => [2, 3, 4] => 5
また分割引数では残余引数も定義できる の中で残余引数も定義できる 1 2 # () def test(a, (b, *c)) 3 4 5 6 7 a + b + c.sum end メソッドの引数: # a = 1, b = 2, c = [3, 4] pp test(1, [2, 3, 4]) 8 9 10 11 # => 10 12 13 14 15 16 17 a + b + c + d.sum + e end こんな感じで複雑にネストして書くこともできる # def test2((a, (b, (c, *d)), e)) メソッドの引数: # a = 1, b = 2, c = 3, d = [4, 5], e = 6 pp test2([1, [2, [3, 4, 5]], 6]) # => 21 ただし、分割引数ではオプショナル引数は定義できない 1 2 3 # error: syntax error, unexpected '=', expecting ')' def test(a, (b, c = 2)) end
キーワード引数 (keyword parameter) 値を渡す時に名前を指定できる引数 `名前:` という形で仮引数を定義する 値を渡す時に名前を指定するので順番に依存せずに渡すことができる 1つ目に渡した値が1つ目の引数で受け取るとは限らない キーワード引数には以下の定義方法がある 必須引数 (required parameter) オプショナル引数 (optional parameter) 残余引数 (rest parameter)
メソッドに値を渡す時に `**` を付けると `Hash` が展開された状態で値が渡される 1 2 3 4 5 6 7 8 9 10 def test(a:, b:, c:) { a: a, b: b, c: c } end hash = { a: 1, b: 2, c: 3 } の中身を展開してキーワード引数に値を渡す と同じ意味 # Hash # test(a: 1, b: 2, c: 3) pp test(**hash) # => {:a=>1, :b=>2, :c=>3} またキーワード引数は位置引数よりも後に定義する必要がある 1 2 3 4 5 6 7 # OK def test(a, b:) end # NG: syntax error, unexpected local variable or method def test(b:, a) end
ちなみに `key => value` という形で渡すこともできる 1 2 3 def test(a:) a end 4 5 6 pp test(:a => 42) # => 42
必須引数 (required parameter) 必ず値を渡す必要があるキーワード引数 定義した必須引数に値を渡さないとエラーになる 名前 という形で引数を定義する 1 2 3 4 5 # : def circle_area(radius:, pi:) radius * radius * pi end 6 7 8 9 # : # radius = 4, pi = 3 pp circle_area(radius: 4, pi: 3) # => 48 10 11 名前 という形で引数を渡す メソッドの引数: # error: `circle_area': missing keyword: :pi (ArgumentError) pp circle_area(radius: 4) 名前を指定するので値を渡す順番に依存しない 1 2 3 4 5 6 7 def circle_area(radius:, pi:) radius * radius * pi end 引数の順番が異なっても渡すことができる メソッドの引数: # # radius = 2, pi = 3.14 pp circle_area(pi: 3.14, radius: 2) # => 12.56
オプショナル引数 (optional parameter) デフォルト値を設定して定義するキーワード引数 必須引数とは違いメソッドに値を渡さなくてもエラーにならない その場合はデフォルト値が変数に代入される 名前 デフォルト値、という形で引数を定義する 1 2 # : def circle_area(radius:, pi: 3.14159) 3 4 5 6 radius * radius * pi end 7 8 9 10 11 12 デフォルト値のあるキーワード引数は省略できる # メソッドの引数:radius = 2, pi = 3.14159 # pp circle_area(radius: 2) 明示的に値を渡すこともできる メソッドの引数: # => 28.27431 # # radius = 4, pi = 3 pp circle_area(radius: 4, pi: 3) # => 48
オプショナル引数はキーワード引数のどの位置でも定義できる 1 2 def test(a:, b: 2, c:, d: 4) { a: a, b: b, c: c, d: d } 3 4 5 6 end pp test(c: 3, a: 1) # => {:a=>1, :b=>2, :c=>4, :d=>3}
残余引数 (rest parameter) 必須引数やオプショナル引数以外で渡された値を全て受け取るキーワード引数 受け取った値は `Hash` になる `**` を付けて仮引数を定義する を付けて引数を定義する # keyword 引数を Hash として受け取る 1 # ** 2 3 4 def create(**attributes) attributes 5 6 7 8 9 end メソッドの引数: # attributes = {:name=>"Homu", :age=>14} pp create(name: "Homu", age: 14) # => {:name=>"Homu", :age=>14} また残余引数は仮引数を省略する事もできる 1 2 3 4 5 第一引数以外のキーワード引数は受け取らない # def first(a:, **) a end
更に Ruby 3.2 からは変数名を省略した場合でも別のメソッドに引数を渡せるようになる予定 1 2 def foo(a:, b:, c:) a + b + c 3 4 5 6 7 end 8 9 10 11 12 13 14 15 16 17 18 までは変数名を書いて他のメソッドに渡す必要があった で受け取った値をそのまま foo メソッドに渡す # Ruby 3.0 def hoge1(**kwd) # hoge1 foo(**kwd) end からは * だけで他のメソッドに渡すことができるようになった def hoge2(**) # hoge2 で受け取った値をそのまま foo メソッドに渡す # Ruby 3.1 foo(**) end pp hoge1(a:1, b: 2, c: 3) pp hoge2(a:1, b: 2, c: 3) # => 6 # => 6
位置引数にキーワード引数を渡す 位置引数でもキーワード引数を受け取れる その場合は `Hash` としてキーワード引数を受け取る 位置引数でもキーワードを受け取る事ができる 1 # 2 3 4 5 6 def test(kwd) pp kwd # => {:a=>1, :b=>2, :c=>3} end 7 8 # kwd = {:a=>1, :b=>2, :c=>3} test(a: 1, b: 2, c: 3) メソッドの引数:
位置引数とキーワード引数がある場合はキーワード引数が優先される 1 2 def test(a = 1, b: 2) [a, b] 3 4 5 6 7 end pp test(b: 42) # => [1, 42] 8 9 10 11 def test2(*args, **kwd) [args, kwd] end 12 13 14 pp test2(a: 1, b: 2) # => [[], {:a=>1, :b=>2}]
また `**nil` と書くことで『明示的にキーワード引数を受け取らない』と定義することもできる この書き方は Ruby 2.7 で追加された 1 2 3 4 5 6 7 8 9 10 11 def test(a = 1, **) end # OK test(b: 42) def test2(a = 1, **nil) end # NG: no keywords accepted (ArgumentError) test2(b: 42)
キーワード引数の非互換な変更について
Ruby 3.0 からキーワード引数の仕様が変更された
Ruby 3.0 以前では次のように `Hash` オブジェクトをキーワード引数として渡すことが可能だっ
た
1
2
def test(a:, b:)
a + b
3
4
5
6
end
7
# => 3
hash = { a: 1, b: 2 }
p test(hash)
しかし Ruby 3.0 からはこれがエラーになるようになった
1
2
3
4
5
6
7
8
def test(a:, b:)
a + b
end
hash = { a: 1, b: 2 }
# eror: wrong number of arguments (given 1, expected 0; required keywords: a, b) (ArgumentError)
p test(hash)
`Hash` きる オブジェクトをキーワード引数として渡したい場合は `**` を付けることで渡すことがで 1 2 3 4 def test(a:, b:) a + b end 5 6 7 hash = { a: 1, b: 2 } p test(**hash) # => 3 キーワード引数の変更に関しては以下の記事を参照してください Ruby 3.0における位置引数とキーワード引数の分離について
ブロック引数 (block parameter)
ブロックを受け取る事ができる引数
受け取った値は `Proc` オブジェクトになる
`Prco#call`
1
2
3
4
5
6
7
8
9
10
11
12
でブロックの中の処理を呼び出すことができる
名前 でブロック引数を受け取ることができる
# &
def test(&block)
pp block
# => #<Proc:0x000056003b763b58 /path/to/test.rb:11>
メソッドでブロックの処理を呼び出すことができる
# call
block.call(1, 2)
end
メソッドの引数:
#
block = #<Proc:0x00007f03114f59c8 /path/to/test.rb:11>
pp test { |a, b| a + b }
# => 3
ブロック引数は必須引数ではないので引数がない場合は `nil` になる 1 2 3 def test(&block) block end 4 5 6 7 # pp test {} # => nil ブロック引数がない場合は nil になる またブロック引数は1つだけしか定義できない ブロック引数は複数定義できない 1 # 2 3 4 # error: syntax error, unexpected ',', expecting ')' def test(&block1, &block2) end
Ruby 3.1 からはブロック引数は仮引数を省略する事もできる その場合は `&` だけで他のメソッドにブロック引数を渡すことができる 1 2 3 4 def hoge(&block) block.call end 5 6 7 8 def foo(&) # & hoge(&) end 9 10 11 だけでブロック引数を他のメソッドに渡せる pp foo { 42 } # => 42
ブロック引数の仮引数を省略する ブロック引数の仮引数を省略した場合に `yield` というキーワードでブロックの処理を呼び出す ことができる 1 def test 2 3 4 5 6 # test(&block) yield(1, 2) end 7 # => 3 で受け取って block.call(1, 2) しているのと同じ意味 pp test { |a, b| a + b }
`#block_given?` できる 1 2 3 4 def test if block_given? " else 5 6 7 8 end end 9 10 で『ブロック引数が渡されたかどうか』を判定して呼び出しを切り分ける事も ブロック引数がある" "ブロック引数がない" pp test pp test {} ブロック引数がない" ブロック引数がある" # => " # => "
ブロック引数に `&` で値を渡す
ブロック引数に値を渡す場合に `&` を付けて渡すことができる
1
2
3
ブロック引数に
を渡している
#
&:upcase
pp %w(homu mami mado).map(&:upcase)
# => ["HOMU", "MAMI", "MADO"]
`&obj`
でブロック引数に値を渡した時は `obj.to_proc` の値をブロック引数として受け取る
1
def test(&block)
2
3
4
5
end
# :upcase.to_proc
pp test(&:upcase)
を block で受け取る
なので最初のコードは以下と同じ意味になる
1
2
3
は
と同じ事をしている
# :upcase.to_proc.call(it)
it.upcase
pp %w(homu mami mado).map { |it| :upcase.to_proc.call(it) }
# => ["HOMU", "MAMI", "MADO"]
転送引数 (forwarding parameter) 全ての引数を受け取って他のメソッドに渡すことができる引数 `...` という記述で引数を受け取る Ruby 2.7 から追加された新しい引数 1 2 def circle_area(radius, pi: 3.14159) radius * radius * pi 3 4 5 6 end 7 8 9 10 11 12 13 14 15 16 と書くことで全ての引数を受け取る事ができる # ... def debug_circle_area(...) 受け取った引数を全て別の引数に渡すことができる # pp(...) circle_area(...) end pp debug_circle_area(3, pi: 3.14) # => 3 # {:pi=>3.14} # 28.26
また Ruby 2.7.3 からは `test(name, ...)` のように位置引数と組み合わせる事もできる
1
2
3
4
5
6
7
8
だけを位置引数として受け取る事ができる
# name
def test(name, ...)
pp name
# => "homu"
pp(name, ...)
# => "homu"
# => {:age=>14}
9
10
11
end
12
test("homu", age: 14)
ただし、キーワード引数と組み合わせる事はできないので注意
1
2
def test(name: , ...)
end
ブロックの引数について ブロックの引数でも基本的にはメソッドの引数と同じように定義する事ができる 1 2 block = proc { |a, b, c = 3, (d, e), f:, g: 7, **h, &i| [a, b, c, d, e, f, g, h, i.call] 3 4 5 6 } pp block.call(1, 2, [4, 5], f: 6, h: 8, j: 9) { 10 } # => [1, 2, 3, 4, 5, 6, 7, {:h=>8, :j=>9}, 10] ただし、次のケースでメソッドの引数とは異なる点がある
ブロックの引数はデフォルトで『分割引数』として値を受け取る ブロックの引数はデフォルトでは『分割引数』として受け取る なので引数が2つ以上あるのブロックに配列を渡すと次のような挙動になる 配列ではない場合は普通に受け取る 1 2 3 4 5 # pp proc { |a, b| [a, b] }.call 1, 2 # => [1, 2] 6 7 8 9 pp proc { |a, b| [a, b] }.call [1, 2] # => [1, 2] 10 11 # a, b # は分割引数として定義される 混じってる場合は配列として受け取る pp proc { |a, b| [a, b] }.call [1, 2], 3 # => [1, 2], 3
また仮引数が1つだけの場合でも末尾に `,` が付いていると分割引数になる がない場合は分割引数にならない 1 2 3 # , pp proc { |a| a }.call [1, 2] # => [1, 2] 4 5 6 7 # , pp proc { |a,| a }.call [1, 2] # => 1 がある場合は分割引数になる これは `Hash` を `each` する時などに注意する必要がある 1 2 3 4 5 6 7 8 9 10 11 12 13 hash = { a: 1, b: 2, c: 3 } ブロックの引数が引数が一つの場合は配列で受け取る # hash.each # => [:a, # [:b, # [:c, { |it| pp it } 1] 2] 3] ブロックの引数が2つの場合は配列を分割して受け取る # hash.each # => [:a, # [:b, # [:c, { |key, value| pp [key, value] } 1] 2] 3]
仮引数よりも少ない数の値を渡す事ができる
ブロックの引数は仮引数よりも少ない数の値を渡す事ができる
1
2
3
4
仮引数は つだが、実引数を つだけ渡すことができる
その場合、値を渡されなかった仮引数は になる
#
2
1
#
nil
pp proc { |a, b| [a, b] }.call(1)
# => [1, nil]
ただし `lambda` や `-> {}` でブロックが定義されている場合は引数の数が厳密にチェックされ
る
必須引数になる
1
2
# error: wrong number of arguments (given 1, expected 2) (ArgumentError)
pp lambda { |a, b| }.call(1)
転送引数には未対応 ブロックの引数では転送引数を定義できない 1 2 3 4 # syntax error, unexpected (..., expecting '|' block = proc { |...| foo(...) }
引数の定義の仕方まとめ 名前 必須引数 (位置引数) オプショナル引数 (位置引数) 残余引数 (位置引数) 後置引数 (位置引数) 分割引数 (位置引数) 必須引数 (キーワード引数) オプショナル引数 (キーワード 引数) 残余引数 (キーワード引数) 書き方 `def test(a, b)` `def test(a = 1, b = 2)` `def test(*args)` `def test(*args, b)` `def test((a, b))` `def test(a:, b:)` `def test(a: 1, b: 2)` `def test(**kwd)` 説明 必ず必要な位置引数 実引数がない場合はデフォルト値が代入され る引数 複数の位置引数を受け取ることができる引数 残余引数以降にかける必須な引数 配列を分割して受け取る事ができる引数 名前を付けて渡せる引数 実引数がない場合はデフォルト値が代入され る引数 複数のキーワード引数を受け取ることができ る引数
名前 書き方 説明 ブロック引数 `def test(&block)` ブロック引数を受け取る特殊な引数 `def test(...)` 転送引数 引数を全て受け取り他のメソッドに渡すことができる特殊な引数
引数の渡し方まとめ 名前 位置引数 splat 引数 キーワード 引数 double splat 引数 ブロック引 数 ブロック引 数 (&渡し) 渡し方 `test(1, 2)` `test(*[1, 2])` `test(a: 1, b: 2)` => 1, :b => 2)` や `test(:a 名前を指定して値を渡す `test(**{ a: 1, b: 2 })` `test { }` や `test do end` `test(&obj)` 説明 仮引数の順番に依存して値を渡す 配列を展開して位置引数に値を渡す。 `test(1, 2)` と 同じ意味 を展開してキーワード引数に値を渡す。 と同じ意味 `{}` や `do end` の中のコードを `Proc` オブジェクト としてブロック引数に値を渡す `obj.to_proc` の結果をブロック引数の値として渡す `Hash` `test(a: 1, b: 2)`
参照 norswap · Ruby Methods, Procs and Blocks クラス/メソッドの定義 (Ruby 3.0 リファレンスマニュアル) Ruby 3.0における位置引数とキーワード引数の分離について Ruby 3: 引数をforwardする`…`記法が第2パラメータでも使えるようになった(翻訳)| TechRacho by BPS株式会社 Defining methods - Ruby Reference Ruby adds support for forwarding arguments to a method, along with the leading arguments | Saeloun Blog