Perlゼミ(サンプルコードPerl入門)

新着情報 8/21(火) 7時更新 Perl入学式 イベント情報

2010年11月30日

サブルーチンの作成方法

  1. Perl
  2. here

 サブルーチンの作成方法を学びましょう。サブルーチンとは、あるまとまった機能に名前をつけて呼び出せるようにする機能のことです。他の言語で関数と呼ばれる機能と同じです。Perlの標準関数についてはPerlの標準関数で解説しています。

サブルーチンの定義

 サブルーチンを定義するには次のようにします。

sub サブルーチン名 {
  # 処理
}

 簡単なサブルーチンとして二つの値の和を求めるtotalという名前をつけたサブルーチンを定義してみましょう。

sub total {
  # (1)引数の受け取り
  my ($num1, $num2) = @_;

  # (2)処理
  my $total = $num1 + $num2;

  # (3)戻り値
  return $total;
}

 (1)引数は「@_」という変数に格納されています。引数にわかりやすい名前をつけるために、$num1と$num2という変数に代入しなおしています。(2)二つの値を合計しています。(3)戻り値はreturn関数を使って返却することができます。

サブルーチンの呼び出し

 サブルーチンを呼び出すには次のようにします。引数を渡して、処理した結果を戻り値として受け取ることができます。

戻り値 = サブルーチン(引数);

 では先ほど作成した、total関数を呼び出してみましょう。

use strict;
use warnings;

# (1)引数に渡す値
my $num1 = 1;
my $num2 = 2;

# (2)サブルーチンの呼び出し
my $total = total($num1, $num2);

# (3)サブルーチンの定義
sub total {
  my ($num1, $num2) = @_;

  my $total = $num1 + $num2;

  return $total;
}

 (1)引数に渡すための値です。(2)サブルーチンの呼び出しです。戻り値は$totalに代入されます。1と2を足した結果が返ってくるので$totalは3になります。(3)サブルーチンの定義は、呼び出しの下におくことも可能です。サブルーチンの定義の読み込みは、コンパイル時に行われるからです。

サブルーチンの引数

 サブルーチンの引数の受け取り方について解説します。

ひとつの引数を受け取る

 ひとつの引数を受け取るときによく使われるのはshift関数を使う方法です。

sub func {
  my $arg = shift;
}

 サブルーチンの中でshift関数を呼び出したときは「@_」がshift関数の暗黙の引数になります。つまり上記は

sub func {
  my $arg = shift @_;
}

 と同じになります。

複数の引数を受け取る

 複数の引数を受け取るときによく使われるのはリスト代入という方法です。

sub func {
  my ($arg1, $arg2) = @_;
}

 @_のひとつ目の要素は$arg1に、ふたつめの要素は$arg2に代入されます。

 また引数が同一種類の場合は、配列に受け取るようにします。

sub func {
  my @args = @_;
}
引数に直接アクセスする

「@_」は配列ですが、この配列に直接アクセスすることも可能です。

#第一引数
$_[0]

#第二引数
$_[1]

この書き方は可読性を下げますので、パフォーマンスがどうしても必要という場合以外は使わないことをお勧めします。

サブルーチンの引数に配列を渡す

サブルーチンに、配列を渡すことができます。

# 渡す側
my $num_total = sum(@nums);

#受け取る側
sub sum{
  my @nums = @_; 
  # 処理
}
サブルーチンの引数にハッシュを渡す

 サブルーチンに、ハッシュを渡すこともできます。受け取る側では、@_をハッシュに代入してあげます。Perlでは配列の中身はリストですので、ハッシュに代入することができます。

# 渡す側
my $examin_total = sum_examin(%examin); 

# 受け取る側
sub sum_examin{
  my %examin = @_;
  # 処理
}
サブルーチンに複数の配列を渡したい

 サブルーチンに複数の配列を渡したい場合は配列のリファレンスとして渡す必要があります。

my @array1;
my @array2;

func(\@array1, \@array2);

sub func {
  my ($array1, $array2) = @_;
}

 以下のように二つの配列を渡してしまうとひとつの配列になってしまいうまくいきません。

my @array1;
my @array2;

func(@array1, @array2);

sub func {
  # ひとつの配列になってしまう
  my @array = @_;
}
サブルーチンに配列とハッシュを区別して渡す

サブルーチンに配列とハッシュを両方わたしたいときはどうすればいいでしょうか。そのような場合は、配列のリファレンス、ハッシュのリファレンスを使う必要があります。

# 渡す側
my $max_num = summary([1, 2, 3], {how => 'max'});

# 受け取る側
sub summary {
  my ($nums, $option) = @_; 
  # 処理                            
}
サブルーチンの引数で「ハッシュ」と「ハッシュのリファレンス」の両方を受け取れるようにする

 サブルーチンでハッシュあるいはハッシュのリファレンスを受け取るには次のように記述します。

func(name => 'Ken', age => 19);
func({name => 'Ken', age => 19});

sub func {
  # 場合に応じてハッシュのリファレンスに変換
  my $arg = ref $_[0] eq 'HASH' ? $_[0] : {@_};
}

 引数がハッシュのリファレンスだった場合は、そのまま代入をおこない、ハッシュだった場合は、ハッシュのリファレンスに変換します。$_[0]は引数である@_の一つ目の要素です。

引数の受け取り方の典型的なパターン

典型的な引数の受け取り方のパターンを紹介します。

(1) 複数のスカラー
search('aiueo', 'eo', 2);

sub search {
  my ( $str, $search, $offset ) = @_;
}

 リストで受け取って、受け取り側でリストのそれぞれの値をスカラーに代入します。

(2) シンプルなリスト
average(1 ,2 ,3 ,4 ,5);

sub average {
  my @nums = @_;
}

 リストで受け取って、配列に代入します。

(3) ひとつのスカラーとリスト
search_file('file', 'apple', 'dog');

sub search_file {
  my ($file, @search_list) = @_;
}

 第1引数はスカラーに代入、第2引数以降は配列に代入します。

(4) シンプルなハッシュ
search_arg_hash(str => 'aiueo', search => 'eo', offset => 2);

sub search_arg_hash{
  my %arg = @_;
  my ($str, $search, $offset) = @arg{'str', 'search', 'offset'};
}

 受け取り側で、ハッシュに代入します。引数の個数が増えた場合は、ハッシュを用いて、引数に名前を与えてあげたほうが、親切なインターフェイスになります。

 ハッシュをスカラーに代入しなおす必要は必ずしもありませんが、代入しなおしたほうが見やすくコーディングしやすくなることが多いです。

(5) ひとつのスカラーとハッシュ
parse_file('in_file', out_file => 'out_file', search_path => 'dir');

sub parse_file{
  my ($in_file, %opt) = @_;
  my ($out_file, $search_path) = @opt{'out_file', 'search_path'};
  return;
}

 第1引数をスカラーに、第2引数以降をハッシュに代入します。第一引数が必須の引数で、そのほかの引数はオプションと考えられる場合は、このインターフェイスが使えます。

サブルーチンの戻り値

スカラ値を戻り値として返却

 サブルーチンの戻り値としてはスカラ値を返すのが基本です。

sub func {
  my $name = 'Ken';

  return $name;
}
配列やハッシュを戻り値として返却

 Perlではリスト(配列やハッシュ)を返却することもできます。

func {
  my @nums = (1, 2, 3);

  return @nums;
}

ただし、この方法はあまりお勧めしません。以下で解説する「配列のリファレンス」「ハッシュのリファレンス」を返す方法をお勧めします。

またwantarray関数で、呼び出しもとのコンテキストに応じて引数を返却することもできますが、余りお勧めしません。コンテキストに応じて戻り値を変えるとユーザは、スカラコンテキストを強制するために、ある位置では「scalar func()」という記述をせざるを得なくなるのが理由です。

リファレンスを戻り値として返却

 配列のリファレンスやハッシュのリファレンスもスカラ値ですので戻り値として返すことができます。

# 戻り値として配列のリファレンスを返す
sub func {
  my $nums = [1, 2, 3];

  return $nums;
}

# 戻り値としてハッシュのリファレンスを返す
sub func {
  my $score = {math => 100, english => 90};

  return $score;
}
単独のreturn

単独のreturnは、スカラーコンテキストでは、未定義値 undef、リストコンテキストでは、空リスト () を、 を返します。

sub func_name {
  # 処理 ...
  return;
}

未定義値を返したい場合は「単独のreturn」を使うのが、慣習になっています。「return undef」とするのは利点もあるのですが、利用頻度は少ないようです。

デフォルト値の設定

 サブルーチンの引数にデフォルト値を指定しておきたい場合があります。そのような場合、引数が、未定義ならば、デフォルト値を設定するという風に記述します。

sub num {
  my $num = shift;
  unless (defined $num) {
    $num = 0;
  } 
}

Perl 5.10からは便利な「defined-or演算子」が導入されたので次のように書くこともできます。左辺が未定義だった場合は、右辺の値が代入されます。

sub num {
  my $num = shift;
  $num //= 0;
}

エラー処理

サブルーチンにおけるエラー処理の方法を解説します。

undefを返す方法

一番簡単な方法はサブルーチンが失敗したときに「undef」を返す方法です。単独のreturnを使ってundefを返します。

sub foo {
  
  my $error;
  
  # ...
  
  if ($error)
    return;
  }
}

呼び出し側では、戻り値をチェックします。

my $ret = foo();

unless (defined $ret) {
  # エラー処理
}
例外を投げる方法

お勧めの方法は、エラーが発生したときに例外を投げるものです。die関数を使って例外を投げます。

sub foo {
  
  my $error;
  
  # ...
  
  if ($error)
    die "Error";
  }
}

もしモジュールの中で例外を投げる場合は、Carpモジュールのcroak関数を利用しましょう。呼び出し元の情報がわかりやすいです。

use Carp 'croak';

sub foo {
  
  my $error;
  
  # ...
  
  if ($error)
    croak "Error";
  }
}

呼び出し側では次のようにして例外をキャッチします。evalを使うことで、例外を捕獲できます。evalブロックの最後にセミコロンが必要なので注意しましょう。

eval {
  foo();
};

if (my $error = $@) {
  # エラー処理
}

例外が発生した場合は「$@」という特殊変数に、エラーの内容が格納されます。「$@」はグローバル変数で上書きされてしまう可能性があるので、すぐにレキシカル変数に代入しておくのがお勧めです。

例外処理についての詳しい解説は「Perlの「例外処理」の仕組み - エラーの通知と検知」をご覧ください。

サブルーチン演習

サブルーチンをきちんと理解するための演習問題を作成しました。

学べるテーマ

CSV、配列の配列、ハッシュの配列、最大値と最小値、並び替え、バブルソート、昇順、降順

サブルーチンへのリファレンス

サブルーチンのリファレンスについての解説です。


学べるテーマ

サブルーチンのリファレンス、ポリモーフィズム、ディスパッチテーブル、シグナルハンドラ、イベント駆動型プログラミング

サブルーチンのテクニック


関数の括弧の省略の規則

 標準関数の括弧は使用しても使用しなくてもかまいません。

# 括弧あり
print('Hello');

# 括弧なし
print 'Hello';

 モジュールからインポートした関数の場合も括弧を使用してもしなくてもかまいません。

# モジュールからインポートした関数
use Carp 'croak';
croak 'Error';

 関数の定義が関数を使用する位置より後ろにある場合は括弧が必須になります。

# 関数定義が後ろにある場合は括弧は必須
func();

sub func {
  ...
}

 括弧を省略するかどうかにはこれといった判断基準はありません。「ほかの人が読みやすいかどうか」と「美感」で決めてください。

 ※プロトタイプとの関係については、プロトタイプは非推奨なので書きません。

サブルーチンを再定義する(モンキーパッチ)

 Perlでは一度行ったサブルーチンの定義を再定義することが可能です。

sub sum { ... }
no warnings 'redefine';
sub sum { ... }

 サブルーチンを再定義すると、再定義の警告がでます。これを消すのにno warnings 'redefine';という記述を行うことで、警告を消すことができます。

 サブルーチンを上書きすることは、モンキーパッチとも呼ばれることがあります。バグがあるサブルーチンを発見した場合に、一時的に、サブルーチンを上書きして、パッチを当てるという使い方ができます。

caller関数 - 実行している関数名を取得

 実行している関数名を取得するにはcaller関数を使用します。caller関数については「caller関数 - 実行している関数名を取得」をご覧ください。

呼び出し元のサブルーチンの引数を取得する

 caller関数を使用すれば、関数の呼び出し元のパッケージ名、サブルーチン名などを取得することができます。さらに呼び出し元のサブルーチンの引数を取得することも可能です。

 呼び出し元の関数の引数を取得するにはcaller関数をDB名前空間内でリストコンテキストで呼び出します。@DB::args に呼び出しもとの関数の引数が設定されます。DBはデバッグに利用されるモジュールです。名前空間をDBに一時的に変更するので、ブロックで囲っておきましょう。ブロックが終わると元の名前空間に戻ります。

sub a2 {
  {
    # DBパッケージに変更
    package DB; 
    
    # caller関数をリストコンテキストで呼び出すと
    my @c = caller 1;
    
    # @DB::argsに引数が格納される    
    my @args = @DB::args;
  }
}
サブルーチンのオートロード

Perlでは、サブルーチンが定義されていなかった場合に実行される関数を定義するオートロードという機能があります。

サブルーチンの動的な作成

Perlではサブルーチンを動的に作成することができます。

クロージャーの作成

Perlにおける「クロージャー」の作成については「Perlで「クロージャー」を作成する方法」をご覧ください。

サブルーチンに関する読み物

Perlの標準関数の一覧

Perlの標準関数の一覧を見たい場合は「Perlの関数の一覧」をご覧ください。

  1. Perl
  2. here

投稿したコメントは管理者が承認するまで公開されません。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証