今回はメソッド定義です。 メソッド定義はRubyの核心ですが、今回はトップレベルに限って説明します。 この限定によって、内容はかなり易しくなっています。
トップレベルに限ればメソッド定義はCの関数定義とほとんど変わりません。
メソッド定義と実行
メソッドはdefからendまでで定義をすることができます。
def example print "Hello world.\n" end example
このプログラムを説明しましょう。
- defの後にメソッド名を書く。
このメソッドは
example
という名前のメソッド。 - endの前までがメソッドの本体。 ここでは「Hello world.と表示する」ことを定義。 定義中は実行はしない。 定義と実行は別
- メソッドを呼び出すにはメソッド名を書く。 メソッドは呼び出されると、自身を実行する
このプログラムexample4.rb
というファイルの保存し、実行すると次のようになります。
$ ruby example4.rb Hello world. $
定義したメソッドは何回でも呼び出せます。
def example print "Hello world.\n" end example example example
これを実行すると
$ ruby example4.rb Hello world. Hello world. Hello world. $
となります。 また、前回学んだイテレータを使うこともできます。
def example print "Hello world.\n" end 3.times do example end
実行結果は前と同じです。
$ ruby example4.rb Hello world. Hello world. Hello world. $
Cを学んだ人ならば、メソッド定義はCの関数定義に似ていると思うでしょう。 現時点ではそのような理解で良いと思います。
パラメータと引数
メソッドにはパラメータを付け加えることができます。 パラメータは括弧の中にコンマで区切って書きます。
def sum(a, b) a + b end print sum(5, 10) print "\n"
実行すると15
が表示されます。
sum
メソッドには2つのパラメータa
とb
がある- メソッド
sum
はa + b
を計算する - メソッド定義で最後に計算された値が、そのメソッドが実行されたときの「値」になる
print
の引数はsum(5, 10)
である。sum(5, 10)
はメソッドsumに引数5と10を与えて実行したときの「値」である。 5と10はパラメータのaとbに代入され、メソッドにより5+10=15が計算され、15が値として返ってくる。 したがって、printは15を表示する- 最後にprintは改行を画面に出力する
「パラメータ(parameter)」と「引数(argument)」という言葉の区別ですが、
- メソッド定義でメソッド名の後ろの括弧にある文字(aやb)はパラメータ
- メソッド呼び出し(メソッドを実行すること)のときにメソッド名の後ろの括弧につけるオブジェクト(5や10)が引数
です。
Rubyでは括弧を省略することができます。 そのとき必要に応じて空白を入れて区切りを明確にします。
def sum a, b ... ... ... print sum 5, 10
括弧は演算の順序を示すときにも使われます。
(2+3)*(4+5)
この括弧は省略できません。 省略すると
2+3 * 4+5
これは、2+12+5=19
になってしまうからです。
*
の両側に空白があったからといって、2+3
と4+5
を先に計算してはくれません。
Rubyではメソッド名と左括弧の間に空白を入れないことが大事です。 一般にRubyではメソッドの括弧を省略しそこに代わりの空白を入れることが可能なので、構文の解釈に曖昧さが生じます。
def double x 2*x end print double (2) + 3 print "\n" print double(2) + 3 print "\n"
これを実行すると
10 7
と表示されます。
最初のdoubleの呼び出しではdouble
と(
の間に空白があるので、メソッドの括弧が省略され、(2)
が計算の順序を表す括弧だと解釈されたのです。
それで、まず(2)+3=5を計算して、その5をメソッドdoubleに引数として渡し、2倍され、10が表示されたのです。
つまり、
double((2)+3)
と解釈されたのです。
2番めのdoubleの呼び出しではdouble
の直後に(
があるので、括弧が引数を表す括弧だと解釈され、2が倍になって4、そのあと3が加えられて7が表示されました。
(double(2))+3
このようなことが生じるのは、Rubyが括弧の省略を許しているためです。 とにかく、メソッドの括弧はメソッド名の直後に書くようにしてください。
if文
多くの言語と同じようにRubyにもif文があります。
def even_or_odd(n) if n.even? print "偶数です\n" else print "奇数です\n" end end even_or_odd(3) even_or_odd(6)
実行すると
奇数です 偶数です
となります。
- メソッド名にアンダースコア(
_
)も使える - パラメータ
n
は整数だと仮定する。整数のメソッドeven?
を呼び出す。 このメソッドはnが偶数ならtrue(真)、そうでなければfalse(偽)を返す。 - if文では、ifの後ろが真であれば直後を実行し、偽であればelse以下を実行する。 なおif文の「真」とは、「falseでもnilでもない」こと。 falseやnilもオブジェクトの一種。 したがって、整数の0や空文字列""は真とみなされる。
ifの右側を「条件」といいますが、ここにはいろいろな演算子が使えます。 良く用いられるのは
==
等しい>
左が大きい。>=
左が大きいかイコール<
右が大きい。<=
右が大きいかイコール
などです。
- else以下は省略できる
- ifとelseの間にelsifを入れることができる。 前のif(またはelsif)の条件が偽でelsifの条件が真のとき、直後の文が実行される
再帰呼出し、パラメータのスコープ
メソッドのパラメータはそのメソッドの中でのみ有効です。 これはメソッド定義でもメソッド呼び出しでもそうです。 これをパラメータのスコープといいます。 スコープは有効範囲ともいいます。
メソッドが複数回呼び出されるとき、それぞれの呼び出しに対応するパラメータはすべて別変数になります。 このことは再帰呼出しをするときに重要になります。
def fact(n) if n<1 nil elsif n==1 1 else n*fact(n-1) end end print fact(5) print "\n"
これを実行すると
120
と表示されます。
- ここでは引数nは整数であると想定する
- 引数nが1より小さければnilを返す
- 引数nが1ならば1を返す
- それ以外(1より大きな整数)のときは、nにn-1のときのfactの値を掛けて返す
最後が複雑ですが、順に考えればわかりやすいです。
- n=2のときは「n=1のときのfactは1なので、2*1=2」
- n=3のときは「n=2のときのfactは2なので、3*2=6」
- n=4のときは「n=3のときのfactは6なので、4*6=24」
- n=5のときは「n=4のときのfactは24なので、5*24=120」
このメソッドは定義の中で自分自身を呼んでいます。 これを「再帰呼出し」といいます。 再帰呼出しのとき、そのどの呼び出しにおいてもパラメータは別物なので、このような計算結果になります。
再帰呼出しは、この例の階乗(factorial)計算に限らず、使えるケースが少なくありません。