SEEDS Creator's Blog

読者です 読者をやめる 読者になる 読者になる

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

html IT perl プログラミング

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

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

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

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

コンテキストとは

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

  • スカラーコンテキスト
  • リストコンテキスト



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

1         # 数値
'hoge'    # 文字列
$hoge     # スカラー変数
\@hoge    # リファレンス


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

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


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

代入

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

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

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


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

# 左辺がリスト、右辺もリスト
my @a = (1, 2, 3);
my @b = @a;
my ($a, $b) = (1, 2);
my ($a, $b) = @list;

my %a = (a => 1, b => 2);
my %b = %a;


配列とハッシュは共にリストコンテキストになるので、相互代入することができます。 実は、Perlのハッシュで使われている「=>」は、「,(コンマ)」と等価です。

my @a = (a => 1, b => 2);  # -> ('a', 1, 'b', 2)
my %b = @a                 # -> (a => 1, b => 2)

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


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

# 配列リファレンス
my $array_ref = \@a;

# ハッシュリファレンス
my $hash_ref = \%a;

# 無名配列リファレンス
my $array_ref = [1, 2, 3, 4];

# 無名ハッシュリファレンス
my $hash_ref = { a => 1, b => 2 };


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

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


for文

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

for my $a ( 1, 2, 3 ) {}

for my $a ( @array ) {}

for my $a ( @{ $array_ref } ) {}


関数

関数の引数は、無名配列変数の「@_」で受け取られます。 左辺がリストコンテキストである場合の代入だと考えると良いでしょう。

func($a, $b);

sub func {
    my ($a, $b) = @_;
}


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

func($a, \@list);

sub func {
    my ($a, $list_ref) = @_;

    my @list = @{ $list_ref };
}


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

# 文字列を返す(返り値はスカラーコンテキスト)
sub func1 {
    return 'a';
}
my $result = $func1();


# 配列を返す(返り値はリストコンテキスト)
sub func2 {
    my @list = (1, 2, 3);
    return @list;
}
my @result = func2();
my ($a, $b, $c) = func2();


# 配列リファレンスを返す(返り値はスカラーコンテキスト)
sub func3 {
    my @list = (1, 2, 3);
    return \@list;
}
my $result = func3();


wantarrayを使うと、関数呼び出し側のコンテキストによって、 返り値のコンテキストを変更することができます。

sub func1 {
    my @a = (1, 2, 3, 4);

    if (wantarray) {
        return @a;
    } else {
        return \@a;
    }
}

# リストコンテキストで受け取る
my @list = func1();

# スカラーコンテキストで受け取る
my $list = func1();

参考ページ

この他にも色々なパターンや例外があるので、後は以下のようなページを参考にして下さい。 コンテキストがわかっていれば、それぞれのパターンについても覚えやすくなるのではないかと思います。