第8章 サブルーチン
8-1. サブルーチンの定義と呼び出し
サブルーチンとは、スクリプトの内部をモジュール化(部品化)する手法をいいます。いわば自分で関数を作成・定義するための手法です。
このため、サブルーチンは「ユーザ関数」とも呼ばれることがあります。
スクリプトを記述する際に、サブルーチンを作成するメリットとして、次の2点が挙げられます。
- CGIスクリプトの中で、ある処理を何度も反復使用したりする場合に、その処理部分をモジュール化して、呼び出すことで効率的なプログラムを記述することができる。
- CGIスクリプトの記述が長くなると、一般的にスクリプト全体の流れが理解しづらくなるが、このときに、全体的な処理を記述するレベル(サブルーチンの呼び出し)と、個々に細かく処理するレベル(サブルーチンの作成)を分けて、全体の見通しをよくする工夫ができる。
サブルーチンを作成するには、次のような構文で定義します。
サブルーチンの定義 |
---|
sub サブルーチン名 { 処理 } (sub + 半角スペース + サブルーチン名 + ブロック) |
このサブルーチン名の付け方の制約は変数名と同じです。
また、サブルーチンの定義部分はスクリプトのどこに置いても構いませんが、一般的には最後に置かれます。
サブルーチンを呼び出すには次のようにします。
呼び出されたところで、定義されたサブルーチンが呼び出され実行されます。
サブルーチンの呼び出し |
---|
& サブルーチン名 (アンパサンド + サブルーチン名) |
コード例
$x = 80; $y = 55; $z = 75; &answer; sub answer { $total = $x + $y + $z; $mean = $total / 3; print "合計点数は$total点で、平均点数は$mean点です。\n"; }
> 合計点数は210点で、平均点数は70点です。
8-2. 引数と戻り値
サブルーチンとは、ユーザが自由に定義できる関数ですから、サブルーチンに引数を渡したり、またサブルーチン実行後に戻り値を返すこともできます。
引数は配列 @_ に格納されて渡されます。
引数の渡し方 |
&abc(@list); (引数 @list を渡すとき) |
引数の受取り |
@_ (渡された引数は、配列 @_ で受け取る) |
コード例
&answer(80, 55, 75); sub answer { # ここで引数を@_で受け取る ($x, $y, $z) = @_; $total = $x + $y + $z; $mean = $total / 3; print "合計点数は$total点で、平均点数は$mean点です。\n"; }
> 合計点数は210点で、平均点数は70点です。
サブルーチンの戻り値は return を使って戻すことができます。
戻り値の戻し方 |
sub abc { 実行文 return @back; } |
戻り値の受取り |
@list = &abc;(サブルーチンを右辺に定義する) |
($total, $mean) = &answer(80, 55, 75); print "合計点数は$total点で、平均点数は$mean点です。\n"; sub answer { # ここで引数を@_で受け取る ($x, $y, $z) = @_; $total = $x + $y + $z; $mean = $total / 3; # 配列で値を返す return ($total, $mean); }
> 合計点数は210点で、平均点数は70点です。
8-3. 局所化
プログラムが数千行、数万行と膨大になってくると、どうしても使用する変数が重複するようになってきます。
また、重複を回避させるために毎回異なる変数を充てるのにも限度があり、混乱や誤りを招いてしまいますし、膨大なプログラムである程、変数の数を絞ったほうがメモリの節約になります。
そこで、変数をサブルーチンなどのブロック内だけに通用させるようにする必要がでてきます。これを局所化といいます。
局所化という観点に基づいたとき、変数の特性は2つに分けられます。
プログラム(スクリプト)全体で参照可能な変数をグローバル変数といい、サブルーチンなどのブロックの中だけで利用可能な変数をローカル変数といいます。
変数は、初期値としてはグローバル変数となりますので、特に何も定義をしない変数はすべてグローバル変数とみなされます。
変数は、初期値としてはグローバル変数となりますので、特に何も定義をしない変数はすべてグローバル変数とみなされます。
変数をローカル変数として定義する場合には、local または my を使用します(local と my の違いについては次節で説明します)。まずは以下の例を見てみましょう。
これは変数が重複したために期待しない結果になってしまう一例です。
$word = "晴れ"; # グローバル変数 &foo; print "今日は$wordです。\n"; sub foo { $word = "雨"; # グローバル変数 }
> 今日は雨です。1行目で変数 $word に「晴れ」が代入されていますが、2行目のfooサブルーチンが実行されたときに、$word に「雨」が代入されたため、3行目の $word は「雨」で実行されています。
これは変数が重複したために期待しない結果になってしまう一例です。
そこで、次にサブルーチン内の変数をローカル変数で定義して局所化してみましょう。
ちなみに、今回のコード例では my の代わりに local を使用しても構いません。(同じ結果になります)
$word = "晴れ"; # グローバル変数 &foo; print "今日は$wordです。\n"; sub foo { my $word = "雨"; # ローカル変数 }
> 今日は晴れです。サブルーチン内で my を使って変数 $word を局所化したため、6行目で代入された「雨」はサブルーチンを抜けた瞬間消滅してしまいます。 したがって、3行目の変数 $word は期待どおりに「晴れ」が実行されることになります。
ちなみに、今回のコード例では my の代わりに local を使用しても構いません。(同じ結果になります)
8-4. local と my の違い
ローカル変数を宣言する関数として、local と my の2つがありますが、この2つの関数には次のような特性と相違が存在します。
ローカル関数 | Perlバージョン | 局所化の特性 |
---|---|---|
local | Perl5 | 宣言されたサブルーチンから呼び出されたサブルーチンからは参照が可能。 |
my | Perl4, Perl5 | 完全に局所化されるため、localのように、サブルーチンから呼び出されたサブルーチンからも参照することはできない。 |
コード例-1 (local変数)
$word = "晴れ"; # グローバル変数 &foo; sub foo { local $word = "雨"; # local関数で定義 &yesterday; } sub yesterday { print "昨日は$wordでした。\n"; # 5行目の$wordを参照します }
> 昨日は雨でした。コード例-2 (my変数)
$word = "晴れ"; # グローバル変数 &foo; sub foo { my $word = "雨"; # my関数で定義 &yesterday; } sub yesterday { print "昨日は$wordでした。\n"; # 5行目の$wordを参照できない }
> 昨日は晴れでした。
8-5. & と () の省略形
ここからは、応用的な内容です。
サブルーチンを記述するときは、基本は「& + サブルーチン名」であることは前述のとおりです。
ある一定の条件の下で、先頭の & や引数を記述する ( ) を省略して書くことができます。
ある一定の条件の下で、先頭の & や引数を記述する ( ) を省略して書くことができます。
1. 引数がない場合 : () を記述すれば、& は省略可
# 基本形 → 当然OK! &hello(); # 基本形 → これもOK! &hello; # 省略形 → & は省略してOK! hello(); # これはダメ → () がないので、& は必須 hello; # サブルーチン sub hello { print "Hello World!\n"; }
2. 引数がある場合 : サブルーチンの定義より後に来れば、& と () は省略可
# サブルーチン sub hello { my ($wd) = @_; print "$wd\n"; } # 基本形 → 当然OK! &hello("Hello World!"); # 省略形 → & は省略してOK! hello("Hello World!"); # 省略形 → サブルーチンの後なので、& と () は省略してOK! hello "Hello World!"; # これはダメ → このような省略形はない &hello "Hello World!";