LoginSignup
17
17

More than 5 years have passed since last update.

Rubyの引数

Last updated at Posted at 2015-10-31

キーワード引数 (Keyword Arguments)

仮引数の形

def f(hoge: "HOGE", foo: "FOO")
def f(hoge:, foo:)

実引数の形

f(hoge: "AAA", foo:"BBB")

Rubyist Magazine - Ruby 2.0.0 のキーワード引数
Ruby 2 Keyword Arguments

def f(hoge: "HOGE", foo: "FOO") #仮引数
  puts hoge
  puts foo
end

f(hoge: "AAA", foo:"BBB") #実引数
def f(hoge:, foo:) #仮引数
  puts hoge
  puts foo
end

f(hoge: "AAA", foo:"BBB") #実引数

実引数のところがちょっぴりObjective-Cぽい。
Objective-Cと違って順番を変えれるけどね。
実引数でHashを渡しているのに、仮引数では、Hashではなくなり個別の変数に入っている(与えたHashが個別の変数に分解されている)。
いわゆる名前付き引数と思うんだけど違うのかなあ。

Positional Arguments (日本語名は?)

一番普通のやつ。

def f(hoge, foo) #仮引数
  puts hoge
  puts foo
end

f("AAA", "BBB") #実引数

Keyword arguments vs Positional arguments

Keyword argumentsのがコールしてるとこ読みやすいよねえ。
引数の順番も入れ替えれる。
まあVBAのときから名前付き引数がスタンダートって感じよねえ。

可変長引数 (英語名は? Splat?)

可変長引数 - うなの日記
仮引数の形

def f(*hoge)

実引数の形

f("AAA", "BBB")

実引数で与えたものを*で宣言した変数にArray にして入る。

def f(*hoge)  #仮引数
  p hoge #=> ["AAA", "BBB"]
end

f("AAA", "BBB") #実引数
def f(*hoge)  #仮引数
  p hoge #=> [{:hoge=>"AAA", :foo=>"BBB"}]
end

f(hoge: "AAA", foo:"BBB") #実引数

Double Splat(日本語ではなんていうんだろう?)

ruby - What does a double * (splat) operator do - Stack Overflow
Drat! - Ruby has a Double Splat - Firmafon Developers Blog
Ruby and the double splat operator | Simplificator

仮引数の形

def f(**options)

実引数の形

f hoge: "AAA", foo: "BBB"

**で宣言した変数にHashで入る。


def f(**options) #仮引数
  p options #=> {:hoge=>"AAA", :foo=>"BBB"}
end

f hoge: "AAA", foo: "BBB" #実引数

んー

def f(options = {})

との違いがわからんぞ。 Double Splatの方が、実引数に変なのきたときにエラーにしてくれるって感じかな。
はじめは options = {}のシンタックスシュガーが**optionsと思ったんだが...

なぜrailsのActiveRecordの引数で受け取れる形が多様なのか!?

Module: ActiveRecord::FinderMethods — Documentation for rails (4.0.0)

Person.find(1)       # returns the object for ID = 1
Person.find("1")     # returns the object for ID = 1
Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
Person.find([1])     # returns an array for the object with ID = 1

上記呼び出し例を見てもらえばわかるが、実引数に受け取れる形が多様すぎる。

どうして

Person.find(1, 2, 6)
Person.find([7, 17])
Person.find(1) # これは可変長引数(*のやつ)で受け取ってるので配列になるのは自明

こんな風に、配列でうけとったり、そうでなかったりできるのか!?

普通に自分で書くと、

def f(*args)
  p args #=> [[1, 2]]
end

f [1,2]

配列の入れ子になってしまう...

RoRのソースを読み進めると...

    def find_with_ids(*ids)
      raise UnknownPrimaryKey.new(@klass) if primary_key.nil?

      expects_array = ids.first.kind_of?(Array)
      return ids.first if expects_array && ids.first.empty?

      ids = ids.flatten.compact.uniq

      case ids.size

発見!!

ids = ids.flatten.compact.uniq

秘密はここと見た!

def f(*args)
  p args.flatten.compact.uniq #=> [1,2]
end

f [1,2]

ほらね!

実引数でHash渡してるのに仮引数*args

実引数でHash渡してるのに仮引数*argsになってるメソッドがちょいちょいある気がする。簡単にすると以下のように*argsArrayになったやつをHashに戻してた

def f(*args)
  p args #=> [{:hoge=>"AAA", :foo=>"BBB"}]
  other_f(*args)
end

def other_f(args)
  p args #=> {:hoge=>"AAA", :foo=>"BBB"}
end

f hoge: "AAA", foo: "BBB"

Ruby - 可変長引数を引き回す - Qiita
Ruby覚え書き - Qiita

可変長引数を使い回すやつの応用と思われる。

  • 配列の展開
    • 実引数の頭に「*」をつけると配列を複数の引数として渡す事ができる
    • 配列をメソッド呼び出しの引数リストとして渡したいときに便利

参考までに

def f(*args)
  p args #=> [{:hoge=>"AAA", :foo=>"BBB"}]
  other_f(*args)
end

def other_f(*args)
  p args #=> [{:hoge=>"AAA", :foo=>"BBB"}]
end

f hoge: "AAA", foo: "BBB"
17
17
1

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
17
17