Rubyの勉強 (4) - メソッド
メソッド
メソッドはdef〜endで定義する.仮引数を指定できるのでPerlのように@_を用いる必要はない.戻り値は最後に実行した式の値になる.
def fact(n) if n == 0 1 else n * fact(n-1) end end puts fact(5) # 120
引数
引数は以下のようなものを扱える.
param | 通常の引数 |
param = val | デフォルト引数 |
*param | 可変引数 |
&block | ブロック引数 |
デフォルト引数
デフォルト引数は引数を指定しなかった時のデフォルト値を指定する.
def hello(str="Ruby") puts "Hello, #{str}" end hello # Hello, Ruby hello "Perl" # Hello, Perl
可変引数
可変長引数を扱うときは'*'を用いる.すると,Arrayオブジェクトとして利用できる.
def foo(*arg) puts arg.join(' ') end foo("Hello,", "Ruby") # Hello, Ruby foo("Hello,", "Ruby", "and", "Perl") # Hello, Ruby and Perl
ブロック
ブロックは無名の関数のようなもの.Perlではmapやsortやgrepなどの引数として利用されてきた.
例えばPerlのmapでは
@array = map {$_ * $_} 1,2,3,4,5; print "@array\n"; # 1 4 9 16 25
のように利用される.これはRubyでは以下のように書ける.
p [1,2,3,4,5].map {|e| e * e} # [1,4,9,16,25]
ここで,pはオブジェクトを人間が読みやすいよう標準出力に出力するメソッドである.
ブロックはRubyの方が自由に記述でき,例えば,Hash#each_pairはハッシュのキーと値を用いるブロックを引数にとる.
{'foo'=>'bar', 'spam' => 'egg'}.each_pair {|k, v| puts "#{k} => #{v}"} # foo => bar # spam => egg
'{}'の代わりにdo〜endを用いることもできる.
{'foo'=>'bar', 'spam' => 'egg'}.each_pair do |k, v| puts "#{k} => #{v}" end
ブロック引数
ブロックを用いるメソッドはブロック引数を用いて定義する.例えば,Perlのgrepを定義したい場合,
# オブジェクト指向っぽくないです def grep(l, &f) if l.empty? [] else e = l.shift if yield e [e] + grep(l, &f) else grep(l, &f) end end end p grep([0, 1, 2, 3, 4, 5]) {|n| n % 2 == 0} # [0, 2, 4]
yieldはブロック引数をメソッドとして実行する.ブロック引数は一つしか利用できず,最後
の引数にしなければならない.
関数
Rubyは全てがオブジェクトなので,正確な意味での関数はなく,全てはメソッドである.putsなどの組み込み関数はKernelクラスのメソッドである.
irb(main)> Object.respond_to?(:puts, true) => true irb(main)> Kernel.respond_to?(:puts, true) => true
Objectは全てのクラスのスーパークラスであり,Kernelをインクルードしている.respond_to?(name[, priv=false])はオブジェクトがpublicメソッドnameを持つかどうかの真偽値を返すメソッドである.2つ目の引数がtrueの時はprivateメソッドでも真を返す.
シンボル
Object#respond_to?は第一引数に文字列かシンボルを取る.シンボルは関数名を表したりするらしい.':symbol'で表現できる.
irb(main)> :symbol => :symbol irb(main)> :symbol.class => Symbol
スクリプトで定義するメソッド
スクリプトのトップレベルはmainという名のObjectクラスのようである.
puts self # main puts self.class # Object
そこで定義されるメソッドもObjectのメソッドとして定義される
irb(main)> def fact(n) irb(main)> if n == 0 irb(main)> 1 irb(main)> else irb(main)> n * fact(n-1) irb(main)> end irb(main)> end irb(main)> Object.fact(5) => 120
ただし,irbではなくrubyのスクリプトとして実行するとprivate methodであるというエラーが出る.
private method `fact' called for Object:Class (NoMethodError)