まくまくPerlノート
サブルーチンの引数をリファレンスで渡す(参照渡し)
2008-04-30

サブルーチンの引数としてリファレンスを受け取るようにすると、呼び出し元でパラメータとして渡した変数の値を変更することができます。 サブルーチンの呼び出し側でも意識してリファレンス(例: \$val)を渡すようにする必要があります。 C/C++ のポインタとほぼ同様の概念です。

スカラ変数のリファレンスを受け取る

# 渡された引数の中身を変更する
sub replace_value {
    my($ref) = @_;  # スカラ変数のリファレンスを受け取る
    $$ref = 200;    # デリファレンスして代入すると呼び出し元のスカラ変数を変更
}

my $val = 100;
&replace_value(\$val);  # 呼び出し側ではリファレンスを渡す
print $val;             #=> 200

配列変数のリファレンスを受け取る

# 渡された配列に値を追加する
sub push_something {
    my($ref_array) = @_;    # 配列変数のリファレンスを受け取る
    push @$ref_array, 100;  # 呼び出し元の配列を変更
}

my @arr;
&push_something(\@arr);  # 呼び出し側ではリファレンスを渡す
&push_something(\@arr);  # 〃
&push_something(\@arr);  # 〃
print "@arr\n";          #=> '100 100 100'

リファレンス自体はスカラ値として扱われるので、配列のリファレンスを渡した場合も $ref_array のように $ の付いた変数名となることに注意してください。 このリファレンスをデリファレンスするときは、配列として扱うので、@$ref_array のように @ を付けてデリファレンスすることになります。

リファレンスで渡した配列を shift で取り出すときの注意

例えば、次のように配列をリファレンスでサブルーチンに渡した場合、

hoge(\@arr);

次のように shift で取り出した配列リファレンスをデリファレンスして参照しようとするのは間違いです。

sub hoge {
    my @arr = @{shift};  # NG! これでは @shift という配列変数を参照してしまう
}

@{shift} が、変数 @shift ではないということを知らせるために何らかの工夫をしなければいけません。 例えば、以下のようにすれば、正しく shift で取り出した値をデリファレンスしてくれます。

my @arr = @{shift()};
my @arr = @{+shift};

参考: 『Effective Perl』

2008-04-30