hero_picture

Perlのコンテキストについて

Perlを書いていると次のような部分で引っかかることがあります。

  • スカラー変数($hoge)と配列変数(@hoge)のどちらを使うか
  • 関数の引数の渡し方
  • 関数の返り値の受け取り方

これらは様々なパターンがあるので、Perlを普段から書いていないと迷ってしまいます。

Perlには「コンテキスト」という考えがあります。

コンテキストを理解すれば、すべてのパターンを覚えなくとも、上であげたことが大体わかるようになってきます。

コンテキストとは

コンテキストは、次の二種類あります。

スカラーコンテキストとは以下のようなものが書かれている場所をいいます。

11         # 数値
2'hoge'    # 文字列
3$hoge     # スカラー変数
4\@hoge    # リファレンス
5

リストコンテキストとは以下のようなものが書かれている場所をいいます。

1@array    # 配列
2%hash     # ハッシュ
3(1, 2)    # リスト
4

Perlプログラムを書いているときは、どちらのコンテキストになっているのかを意識するようにします。

代入

代入では、左辺と右辺がそれぞれどちらのコンテキストになっているのかを意識します。

ほとんどの場合は、同じコンテキストになるようにします。

左辺も右辺もスカラーコンテキストの場合。

1# 左辺がスカラー、右辺もスカラー
2my $a = 'test';
3my $b = $a;
4

左辺も右辺もリストコンテキストの場合。

1# 左辺がリスト、右辺もリスト
2my @a = (1, 2, 3);
3my @b = @a;
4my ($a, $b) = (1, 2);
5my ($a, $b) = @list;
6my %a = (a => 1, b => 2);
7my %b = %a;
8

配列とハッシュは共にリストコンテキストになるので、相互代入することができます。

実は、Perlのハッシュで使われている「=>」は、「,(コンマ)」と等価です。

1my @a = (a => 1, b => 2);  # -> ('a', 1, 'b', 2)
2my %b = @a                 # -> (a => 1, b => 2)
3my %a = ('a', 1, 'b', 2);  # -> (a => 1, b => 2) ※順番は保持されない
4

リファレンスはスカラー値なので、スカラー変数で受け取ります。

1# 配列リファレンス
2my $array_ref = \@a;
3# ハッシュリファレンス
4my $hash_ref = \%a;
5# 無名配列リファレンス
6my $array_ref = [1, 2, 3, 4];
7# 無名ハッシュリファレンス
8my $hash_ref = { a => 1, b => 2 };
9

配列リファレンスをデリファレンスすると、リストコンテキストになるので、配列変数で受け取ります。

ハッシュのリファレンスも同じです。

1# デリファレンス後はリストコンテキストなので、配列変数で受け取る
2my @a = @{ $array_ref };
3my %a = %{ $hash_ref };
4

for文

for文のカッコの中はリストコンテキストになるので、リストを渡すようにします。

1for my $a ( 1, 2, 3 ) {}
2for my $a ( @array ) {}
3for my $a ( @{ $array_ref } ) {}
4

関数

関数の引数は、無名配列変数の「@_」で受け取られます。

左辺がリストコンテキストである場合の代入だと考えると良いでしょう。

1func($a, $b);
2sub func {
3my ($a, $b) = @_;
4}
5

配列リファレンスを引数にする場合。

1func($a, \@list);
2sub func {
3my ($a, $list_ref) = @_;
4my @list = @{ $list_ref };
5}
6

関数の返り値を受け取る場合も、返り値のコンテキストを意識します。

1# 文字列を返す(返り値はスカラーコンテキスト)
2sub func1 {
3return 'a';
4}
5my $result = $func1();
6# 配列を返す(返り値はリストコンテキスト)
7sub func2 {
8my @list = (1, 2, 3);
9return @list;
10}
11my @result = func2();
12my ($a, $b, $c) = func2();
13# 配列リファレンスを返す(返り値はスカラーコンテキスト)
14sub func3 {
15my @list = (1, 2, 3);
16return \@list;
17}
18my $result = func3();
19

wantarrayを使うと、関数呼び出し側のコンテキストによって、

返り値のコンテキストを変更することができます。

1sub func1 {
2my @a = (1, 2, 3, 4);
3if (wantarray) {
4return @a;
5} else {
6return \@a;
7}
8}
9# リストコンテキストで受け取る
10my @list = func1();
11# スカラーコンテキストで受け取る
12my $list = func1();
13

参考ページ

この他にも色々なパターンや例外があるので、後は以下のようなページを参考にして下さい。

コンテキストがわかっていれば、それぞれのパターンについても覚えやすくなるのではないかと思います。