Perlの関数引数は参照渡し

続・初めてのPerl 改訂版

続・初めてのPerl 改訂版

Perlにおける関数引数は基本的に「参照渡し」だという事がちゃんと分かっていなかったというか、「続・初めてのPerl」の「リファレンス入門」を読んでいるうちに混同してしまっています。

#!/usr/bin/perl

use strict;
use warnings;

my @array = ( "hoge", "foo", "var" );
my $ref = \@array;

foreach my $tmp (@array){ print "before : ", $tmp, "\n"; }

&like_pass_by_value($array[0]);
&edit_function_arg($array[1]);
&edit_array(@array);
&edit_array_element(@array);
&edit_array_reference($ref);

foreach my $tmp (@array){ print "after  : ", $tmp, "\n"; }

# 関数の中で引数をレキシカル変数に代入して使うと、まるで値渡しのようにみえる
sub like_pass_by_value {
    my $tmp = shift;
    $tmp = $tmp."test";
}

# しかし、実際は参照渡しなので、関数引数を直接いじると元の実体を更新することになる
sub edit_function_arg {
    $_[0] = $_[0]."_changed";
}

# ただし、配列を引数として渡した場合、@_は参照渡しではなく値渡し
sub edit_array {
    push @_, "array_add";
}

# しかし、要素単位で見ると参照渡し??
sub edit_array_element {
    $_[2] = "element";
}

# 配列を引数で渡すときは配列の参照を渡すと参照渡しになる
sub edit_array_reference {
    my $ref = shift;
    push @{$ref}, "ref_add";
}

上記のスクリプトの実行結果は以下のようになります。

[user@colinux 20070925]$ ./reference_test.pl
before : hoge
before : foo
before : var
after  : hoge
after  : foo_changed
after  : element
after  : ref_add
[user@colinux 20070925]$

とりあえず大前提として、Perlの関数引数は「参照渡し」が基本で、関数内部でレキシカル変数に代入するとまるで「値渡し」のように思えるだけ、というのはよく理解できたのですが。

関数引数に配列を渡す場合がまだクリアになりません。上記の試しのように動きとしては「配列全体」として扱う場合には、「値渡しのように」というか、サブルーチン内のローカルなスコープのものをいじっているように見えますが、その配列の要素を一個取り出して更新するとそれは外にある実体に影響しています。

配列そのものを渡した場合、その配列自体は「値渡し」だが、その要素単位で取得した場合(変数の場合同様に)「参照渡し」になるということでしょうか。


#ちゃんと理解したらまた書く