Help us understand the problem. What is going on with this article?

[Ruby入門] 08. メソッドを定義する

More than 3 years have passed since last update.

>> 連載の目次は こちら!

メソッドの話はクラスの回に含めようと思ったが、けっこう大きなトピックになったので章立てすることにした。

■ 概要

クラスの外(トップレベル)について

  • Rubyは完全にオブジェクト指向だが、クラスの外(トップレベル)にメソッドを定義して、普通の関数っぽく使える。
  • トップレベルに定義したメソッドは、main という名の Objectクラスインスタンス の private メソッドとして定義される。
  • トップレベルでの self は main を指している
p self           # main
puts self.class  # Object

メソッドに関する共通事項

  • 引数の型が動的なので、オーバーロードはできない
  • メソッド呼び出し側の引数の()は省略できるが、通常は記述する。attr_accessor のように特殊な意味を持つメソッドでは省略する慣習がある。
  • メソッド名や変数名はスネークケースが一般的

・言うまでもないが、全てはオブジェクトなので引数は参照渡しになっている
  ↑ 間違いです!!
tadsan 様よりご指摘頂きました。( ありがとうございます m(_ _)m )
勘違いしやすいので取り消し線で残しておきます。
詳しくは後で整理しますが、ピンと来ない方は↓こちらを参照してください。
値渡しと参照渡しの違いを理解する

■ メソッドの定義の基本

・いちばん単純なメソッド

def hanami
  puts "満開!"
end
hanami

・引数あり

デフォルト値を指定可能

def hanami_with_cat_and_food(cat, food = "鰹節")
  puts "%sが%sを食べる。桜に興味なし!" % [cat, food];
end
hanami_with_cat_and_food("chee")
hanami_with_cat_and_food("miro", "お刺身")

・戻り値あり

returnは省略可能で、その場合はメソッド内の処理で最後に得られた値が戻り値になる。

def wants_list(genre)
  list = {music:%w[player, speaker], fashion:%w[T-shirt, shoes], etc:%w[watch, wallet]}
  return list[genre] || {}
end
p wants_list(:fashion)

・複数の戻り値を返す

def lunch_and_drink
  return %w[カレー パスタ うなぎ].sample, %w[コーヒー 紅茶 黒烏龍茶].sample
end
f, d = lunch_and_drink  # 個別に代入
arr  = lunch_and_drink  # 配列で受け取る

■ キーワード付き引数(引数にラベルを付ける)

・基本的な使い方

def sanpo(animal: "犬", food: "お弁当", to:)
  puts "%s持って%sまで%sとお散歩♪" % [food, to, animal]
end
sanpo(animal: "猫", food: "サンドウィッチ", to:"上野")
sanpo(to:"代々木", food: "ホットドッグ")
sanpo(to:"井の頭公園")
  • どの引数がなにを意味してるのかわかりやすい
  • 定義側は、ラベルと同名の変数として引数にアクセスする
  • 定義側は、デフォルト値をコロンの後ろに指定できる
  • 呼び出し側は、ラベル記述必須
  • 呼び出し側は、引数の順番を気にしなくて良い

・ハッシュをキーワード引数として渡す

def size(width:, height:)
  puts "#{width} x #{height}"
end
hash = {width:55, height:45}
size(hash)

・想定外のキーワード引数をまとめてハッシュとして受け取る

def go_shops(where, cafe:, **shops)
  p shops   # {:fashion=>"ユニクロ", :dinner=>"大戸屋"}
  puts "%sで%s行って%s行って%s行く!" % [where, shops[:fashion], cafe, shops[:dinner]]
end
go_shops("地元", cafe:"ドトール", fashion:"ユニクロ", dinner:"大戸屋")

■ メソッドに処理(ブロック)を渡す

・ブロックだけ渡す

def okini_mesumama
    puts "はいはい、仰せの通り #{yield} しますよ〜だ"
end
okini_mesumama {"お掃除"}

# ちなみに、↑上記は、↓以下と同じ。(& + call は yield と同じ)
def okini_mesumama(&block)
    puts "はいはい、仰せの通り #{block.call} しますよ〜だ"
end
okini_mesumama {"お掃除"}

・引数とブロックを渡す

def okini_mesumama_nandodemo(cnt)
  (1..cnt).each do |i|
    puts "はいはい、#{yield} #{i}回目〜"
  end
end
okini_mesumama_nandodemo(3) {"お掃除"}

・ブロックパラメータを持ったブロックを渡す

def cleaning(cnt)
  item = "掃除機"
  (1..cnt).each do |i|
    puts "はいはい、#{yield(i, item)} お掃除します〜"
  end
end
cleaning(3) do |i, item|
  if (i == 3) then "#{item}でしっかり" else "さらっと" end
end

・ブロックが渡されているかどうか判定する

def work
  if block_given?
    puts "はいはい、仰せの通り #{yield} しますよ〜だ"
  else
    puts "楽しい仕事を優先するよ〜"
  end
end
work
work {"せっせと資料作成"}

■ メソッドをオブジェクトとして扱う

メソッド名をそのまま記述すると実行されてしまうので、Methodクラスのオブジェクトに変換すれば、他のメソッドの引数として渡したりといったやりとりが可能になる。

def power(n); n * n end

# methodメソッドで、メソッドをオブジェクト化して...
pw = method(:power)

def exec_method_obj(arg, fun)
  puts fun.call(arg)
end

# そのオブジェクトをメソッドに渡す
exec_method_obj(3, pw)  # 9

※ちなみに、上記の「call」メソッドは、省略記法があるので注意。

def power(n); n * n end
pw = method(:power)
puts pw[4]   # 16
puts pw.(5)  # 25

■ その他の引数の受け渡し方法いろいろ

・キーワード引数風に指定してハッシュを渡す

def test(args)
  p args
end
test(x:99, y:88)  # {:x=>99, :y=>88}

上記のメソッド定義はキーワード引数になってない。呼び出し側でキーワード引数風に指定して渡すと、メソッド側はハッシュとして受け取れる

・呼び出し側で配列を展開して個別の引数として渡す

def hikisu_ooiyo(num1, num2, num3, num4)
  puts "%d.%d.%d.%d" % [num1, num2, num3, num4]
end
arr = [192, 168, 1, 12]
hikisu_ooiyo(*arr)

・可変数な引数をまとめて配列として受け取る

def go_cafes(where, *shops)
  p shops   # ["スタバ", "タリーズ", "ミスド"]
  puts "%sの%sをはしごする!" % [where, shops.join('と')]
end
go_cafes("駅前", "スタバ", "タリーズ", "ミスド")

・可変数な引数をまとめて配列とハッシュとして受け取る

ここまでやると複雑になっちゃうから多分やらないだろうな〜
でもこんなこともできるってことでいちおう整理しておく。

def hukuzatsu_sugiru(arg, *arr, **hash)
  p arg, arr, hash
end

hukuzatsu_sugiru(1, 2, 3, 4, 5)
  # 1
  # [2, 3, 4, 5]
  # {}
hukuzatsu_sugiru(1, 2, 3, name:"miro", age:9)
  # 1
  # [2, 3]
  # {:name=>"miro", :age=>9}
hukuzatsu_sugiru(1, name:"miro", age:9)
  # 1
  # []
  # {:name=>"miro", :age=>9}
prgseek
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした