おもこん

おもこんは「思いつくままにコンピュターの話し」の省略形です

徒然Ruby(4)トップレベルのメソッド定義

今回はメソッド定義です。 メソッド定義は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つのパラメータabがある
  • メソッドsuma + 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+34+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)計算に限らず、使えるケースが少なくありません。

まとめ

  • トップレベルのメソッドはCの関数(あるいは他の言語の関数や手続き)のように使うことができる
  • メソッドにはパラメータをつけることができる。 パラメータはそのメソッドの中でのみ有効
  • パラメータはメソッド名直後(から次の)まで。 括弧は略すことができる。 そのときは左括弧の代わりに半角空白を入れる
  • メソッドを再帰呼出しすることができる
  • if - elsif - else - end が使える