【Ruby】メソッド

「はじめてのRuby」を読んでのメモ。
今回は7章「メソッド」



Rubyのメソッドは、レシーバによって下の3種類に分けられる。

レシーバがオブジェクト(インスタンス)。最も一般的なメソッド。

p "10,20,30".split(",")    #=> ["10", "20", "30"]
p [1, 2, 3].index(2)       #=> 1
p 100.to_s                 #=> "100"


  • クラスメソッド

レシーバがクラスそのもの。インスタンスを作るような場合に使う。
クラスに関連する操作を行いたい場合にも使う。

Array.new                 # 新しい配列の作成
File.open("some_file")    # 新しいファイルオブジェクトの作成
Time.now                  # 新しい Time オブジェクトの作成

File.rename(oldname, newname)    # ファイル名の変更


  • 関数的メソッド

レシーバがないメソッド。本当に無いわけではなく、省略されている。

print "hello!"    # コンソールに文字列を出力
sleep(10)         # 指定された秒数の間、処理を休止


メソッドの定義

def profile(name,age)
  puts "#{name} さん #{age} さい"
end

profile("secon",20)        #=> secon さん 20 さい
デフォルト値を設定する場合は「引数名 = デフォルト値」と書く。
def profile(name="secon",age)        #デフォルト値の指定
  puts "#{name} さん #{age} さい" 
end

profile(20)             #=> secon さん 20 さい
profile("second",20)    #=> second さん 20 さい


戻り値

return 文を用いることで戻り値を指定できる。
return 文は省略可能(その場合はメソッドの中で最後に得られる値が戻り値になる)。
見かけ上の最後の行が戻り値とは限らない点に注意。

def volume(x,y,z)
  return x * y * z
end

puts volume(2,3,4)    #=> 24
def max(a,b)
  if a > b
    a
  else
    b
  end
end

puts max(10,5)        #=> 10

また、 return の引数を省略した場合には nil が返される

ブロックつきメソッドの定義
def myloop
  while true		# ブロックを実行
    yield
  end
end

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

yield は、ブロックつきメソッドを定義する際にもっとも重要なキーワードである。yield は、メソッドの呼び出しの際に与えられたブロックを実行する。
このプログラムを実行すると num の値を100を超えるまで2倍する。

引数の数が不定なメソッド
def foo(*args)
  args
end

p foo(1,2,3)    #=> [1, 2, 3]
p foo("A","B")  #=> ["A", "B"]
def meth(arg, *args)
  [arg,args]
end

p meth(1)       #=> [1, []]
p meth(1,2,3)   #=> [1, [2, 3]]
def a(a,*b,c)
  [a,b,c]
end

p a(1,2,3,4,5)  #=> [1, [2, 3, 4], 5]
p a(1,2)        #=> [1, [], 2]


キーワード引数

キーワード引数を使うと、引数名と値のペアで引数を渡せるようになる。
下の例では、引数にデフォルト値として0を指定してメソッドを定義している。

def area2(x: 0, y: 0, z: 0)
def area2(x: 0, y: 0, z: 0)
  xy = x * y
  yz = y * z
  zx = z * x
  (xy + yz + zx) * 2
end

p area2(x: 2, y: 3, z: 4)    #=> 52
p area2(x: 2, z: 5)          #=> 20
area2(foo: 2)    #=> unknown keyword: foo (ArgumentError)
# 定義にない引数でパラメータを与えた場合、エラーとなる
def meth(x: 0, y: 0, z: 0, **args)
  [x, y, z, args]
end

p meth(z: 4, y: 3, x: 2)          #=> [2, 3, 4, {}]
p meth(x: 2, z: 3, v: 4, w: 5)    #=> [2, 0, 4, {:v=>4, :w=>5}]
# 定義に存在しないキーワード引数を受け取る
def func(a, b: 1, c: 2)
  [a, b, c]
end

p func(3, c: 5)    #=> [3, 1, 5]
# キーワード引数と通常の引数の組み合わせ
args1 = {x: 2, y: 3, z: 4}
p area2(args1)        #=> 52  

args2 = {x: 2, z: 5}    
p area2(args2)        #=> 20
#ハッシュで引数を渡す


メソッド呼び出しの補足
def foo(a,b,c)
  a + b + c
end

p foo(1,2,3)        #=> 6

args1 = [2,3]
p foo(1, *args1)    #=> 6

args2 = [1,2,3]     #=> 6
p foo(*args2)
#配列を引数に展開
p foo(*args)    #=> wrong number of arguments (2 for 3) (ArgumentError)
#配列の要素の数と引数の数は一致していないといけない



メソッドの引数にハッシュのリテラルを渡す場合、 {} を省略できる。

def foo(args)
  arg
end

p foo({"a"=>1, "b"=>2})   #=> {"a"=>1, "b"=>2} 
p foo("a"=>1, "b"=>2)     #=> {"a"=>1, "b"=>2}
p foo(a: 1, b: 2)         #=> {:a=>1, :b=>2}
def bar(arg1, arg2)
  [arg1, arg2]
end

p bar(100, {"a"=>1, "b"=>2})    #=> [100, {"a"=>1, "b"=>2}]
p bar(100, a: 1, b: 2)          #=> [100, {:a=>1, :b=>2}]
# 最後の引数としてハッシュを渡す