プログラミング言語III講義資料/メソッド

国島丈生(t.kunishi@gmail.com) 

メソッド

Rubyのメソッドについて、ここで整理をしておこう。

メソッド呼び出し

Rubyでメソッドを呼び出すときには次のようにするのであった。

1.to_s
"string".split(//)

この例では、1や "string" といったデータに対して、to_s や split といったメソッドを適用している。メソッドを適用するデータのことをレシーバという。この例では、1や "string" がレシーバである。

メソッド呼び出しは、以下のような形式になる。

レシーバ.メソッド名(引数リスト)
レシーバ.メソッド名 引数リスト # 引数リストをくくるカッコは省略可能

Rubyの場合、どのようなメソッド呼び出しでも必ずレシーバが存在する。printf や p のように一見レシーバを持たないメソッド呼び出しでは、デフォルトのレシーバ self が省略されているとみなされる。(self の意味は後述する)

戻り値

メソッド呼び出しを行うと、必ず何らかの値が返ってくる。これをメソッドの戻り値(または返り値)という。1.to_s の戻り値は "1", "string".split(//) の戻り値は ["s", "t", "r", "i", "n", "g"] である。

メソッドの戻り値をレシーバにして、さらにメソッドを呼ぶことも可能である。この場合、. 演算子は左結合なので、左から順に計算が行われることになる。
13456.to_s.split(//)        #=> ["1", "3", "4", "5", "6"]

メソッドの定義

ここでは、レシーバの情報を使わないタイプのメソッドを例にとって、メソッドの定義の仕方を説明する。レシーバの情報を使うタイプについては、回を改めて説明する。

メソッド定義の構文は次の通りである。

def メソッド名(引数リスト)
  メソッドの本体 # 複数の式を並べて書く
end
def sum(x, y)
  x + y
end
def diff x, y
  x - y
end
sum(1, 2)        #=> 3
diff(2, 1)        #=> 1

メソッド呼び出しのときにはそれらが順次実行され、最後に実行された式の値がメソッドの戻り値になる。上の例では、式 x + y の評価値がメソッド sum の戻り値になる。戻り値として配列やハッシュを返すことももちろん可能である。

メソッドの途中で本体の実行を終了したい場合など、明示的にメソッドの戻り値を指定したい場合は return 式を用いる。

ブロック付のメソッド

ブロックを引数に取るメソッドも、普通のメソッドと同じように定義できる。ただし、いくつか注意すべき点がある。

メソッド内からブロックを呼び出す方法

メソッド内から引数のブロックを呼び出すには yield 式を用いる。
def foo
  yield "bar"
end
foo {|item| puts item}        #=> barと出力
これは、ブロック {|item| puts item} を引数としてメソッド foo を呼び出した例である。メソッド foo の本体の yield 式に来たところで、引数として渡されたブロックを実行する。このとき、yield 式の引数(この場合だと "bar")をブロックに引数として渡す。その結果、ブロックの仮引数 item に "bar" が束縛された状態で puts item が実行され、bar と出力される。

練習問題

1. 整数nを引数として、以下のような出力を行うメソッド fizzbuzz(n) を書け。n が 3 で割り切れるなら Fizz, 5 で割り切れるなら Buzz, 3でも5でも割り切れるなら Fizz Buzz、3でも5でも割り切れないなら n (数字そのもの) を出力する。
2. 負でない2つの整数 x, y (x ≧ y) の最大公約数を求める方法として、ユークリッドの互除法がある。これは、次のような計算を順次繰り返すことで最大公約数を求める。
gcd(x, y) = \left\{ \begin{array}{ll} x & (y = 0) \\ gcd(y, \,x \bmod y) & (y\, \neq \,0) \end{array}
ユークリッドの互除法に基づいて2数x, yの最大公約数を求めるメソッド gcd(x, y) を書け。