fugafuga.write

日々のログ

Ruby 2.x.x 入門 - メソッド定義・キーワード引数 -

メソッド、それは華麗な振る舞い。



メソッド定義の仕方

Rubyでのメソッド定義

def メソッド名(引数1, 引数2, ...)
  処理
end

メソッド名には、アルファベット、数字、アンダースコア_ が使える。
ただし、数字から始まるメソッド名は命名できない。


引数はデフォルト値を持てる。

def hello(name = "Default")
  return "Hello #{name}"
end

puts hello
puts hello("Ruby")

[出力]
Hello Default
Hello Ruby

ただし、引数が複数ある場合、デフォルト値を持たせる引数は引数リストの右側に書く。
デフォルト値が無いものが間に挟まってたりしたらダメ。

# OK
def hello(weight, height, name = "Default")
  return "Hello #{name}"
end

# ダメ
def hello(weight = 50, height, name = "Default")
  return "Hello #{name}"
end

# OK
def hello(height, weight = 50, name = "Default")
  return "Hello #{name}"
end


return は省略できる。

def hello(name = "Default")
  "Hello #{name}"
end

puts hello
puts hello("Ruby")

[出力]
Hello Default
Hello Ruby


return 単体で書くとnil を返す。

def hello(name = "Default")
  return
end

p hello

[出力]
nil

ブロック付きメソッドの定義の仕方

each や times のようなブロックを処理するメソッドの定義の仕方。

def myloop
  while true
    yield
  end
end

num = 1
myloop do
  puts "num => #{num}"
  break if num > 100
  num *= 2
end

[出力]
num => 1
num => 2
num => 4
num => 8
num => 16
num => 32
num => 64
num => 128

yield というキーワードがメソッドに与えられたブロックを表す。


ブロック変数がある場合、

def myloop
  i = 0  # カウンタ機能を持たせる
  while true
    yield(i)  # ブロック変数にカウンタ値を与える
    i += 1
  end
end

num = 1
myloop do |i|  # yield(i) で与えられたカウンタが得られる
  puts "#{i}回目 => #{num}"
  break if num > 100
  num *= 2
end

[出力]
0回目 => 1
1回目 => 2
2回目 => 4
3回目 => 8
4回目 => 16
5回目 => 32
6回目 => 64
7回目 => 128

引数の数が不定なメソッドの定義の仕方

def foo(*args)
  args
end

p foo(1, 2, 3, 4)

[出力]
[1, 2, 3, 4]

[*args] で引数を定義すると、配列で受け取ることができる。


この引数を使うと、
最初と最後の引数だけ固定でその間は省略可能というメソッドが定義できる。

def foo(arg1, *args, arg2)
  [arg1, args, arg2]
end

p foo(1, 2, 3, 4)
p foo(1, 4)

[出力]
[1, [2, 3], 4]
[1, [], 4]

キーワード引数を持つメソッドの定義の仕方

デフォルト値を持ち、引数の順番は関係なく、全く関係ない引数もメソッドに渡せるという夢のような機能。
それがキーワード引数。
Ruby2.0から使えるようになった。

いやまあ、自由すぎるのも良くないと思うけどね。

def total(a: 0, b: 0, c: 0)
  a + b + c
end

p total(a: 1, b: 2, c: 3)
p total(a: 1, b: 2)
p total(a: 1, z: 5)

[出力]
6
3
ArgumentError: unknown keyword: z

呼び出しの時に引数名を指定して値を渡す。
存在しない引数名が指定された場合、エラーとなる。


しかし、存在しない引数を受け取ることができるのがすごいところ。

def total(a: 0, b: 0, c: 0, **args)
  res = 0
  # キーワード指定された引数を足し込む
  res = a + b + c
  
  # args が 空じゃなかったら中身を確認する
  p "**args => #{args}" unless args.empty?
  
  # hashで渡された引数を足し込む
  args.each do |key, val|
    res += val
  end
  return res
end

p total(a: 1, b: 2, c: 3)
p total(a: 1, b: 2)
p total(a: 1, x: 4, y: 5, z: 6)

[出力]
6
3
"**args => {:x=>4, :y=>5, :z=>6}"
16

存在しない引数名で指定された値は、引数名: 値のハッシュで「**args」に渡される。


普通の引数とキーワード引数の組み合わせも可能

def total(a, b: 0, c: 0, **args)
  res = 0
  # キーワード指定された引数を足し込む
  res = a + b + c
  
  # args が 空じゃなかったら中身を確認する
  p "**args => #{args}" unless args.empty?
  
  # hashで渡された引数を足し込む
  args.each do |key, val|
    res += val
  end
  return res
end

p total(1, b: 2, c: 3)
p total(1, b: 2)
p total(1, x: 4, y: 5, z: 6)

[出力]
6
3
"**args => {:x=>4, :y=>5, :z=>6}"
16


キーワード引数で定義されたメソッドは、hashオブジェクトでパラメータを渡すことが可能

def total(a: 0, b: 0, c: 0, **args)
  res = 0
  # キーワード指定された引数を足し込む
  res = a + b + c
  
  # args が 空じゃなかったら中身を確認する
  p "**args => #{args}" unless args.empty?
  
  # hashで渡された引数を足し込む
  args.each do |key, val|
    res += val
  end
  return res
end

# パラメータを作る
param = {a: 2, b: 3, c: 4, x: 9, y: 8, z: 7}

p total(param)

[出力]
"**args => {:x=>9, :y=>8, :z=>7}"
33

まとめ

キーワード引数が衝撃的だった。
もっとテクいことができそうなので書きまくるしか無い。
他の人が書いたコードも読む。



たのしいRuby 第4版

たのしいRuby 第4版

作りながら学ぶRuby入門 第2版

作りながら学ぶRuby入門 第2版