Perl再入門: 2008年6月アーカイブ
use strict;
my @list = ("a", "b", "c");
my $ref = \@list;
# 配列全体を取り出す
print "@{$ref}\n"; # 出力: a b c
print "@$ref\n"; # 出力: a b c
# 配列の要素を取り出す
print "${$ref}[0]\n"; # 出力: a
print "$$ref[0]\n"; # 出力: a
print "$ref->[0]\n"; # 出力: a
省略のルール
- { なんちゃら } が単純なスカラー変数の場合は、{ }を省略できる。 例: @{ $ref } ⇒ @$ref
- ${ なんちゃら }[1] と書ける全てのコードは、なんちゃら->[1] と書ける。 例: ${$ref}[0] ⇒ $ref->[0]
${$ref}[0] ⇒ $$ref[0]
配列のリファレンスをネスト
リファレンスはネストさせることができます。階層構造を持ったデータを作るときに便利です。
use strict;
my @array1 = (1, 2, 3);
my @array2 = (2, 4, 6);
my @all = (\@array1, \@array2);
my $ref = \@all;
# 値を取り出す
print "${${$ref}[1]}[2]\n"; # 出力: 6
print "$ref->[1]->[2]\n"; # 出力: 6
print "$ref->[1][2]\n"; # 出力: 6
# 配列を取り出す
print "@{${$ref}[1]}\n"; # 出力: 2 4 6
print "@{$ref->[1]}\n"; # 出力: 2 4 6
まず、@array1と@array2のリファレンスを作って@allに格納します。次に、@allのリファレンスを作って$refに格納しています。
すると、$refは「配列のリファレンスを格納した配列」のリファレンス ということになります。
デリファレンスの省略記法
2つの法則があります。- ${なんちゃら}[1] と書ける全てのコードは、なんちゃら->[1] と書ける。
- 添え字的なもの間に挟まれている矢印、つまり[1]->[2]とか{'foo'}->{'bar'}とかの矢印は省略できる。
例
${$ref}[1] => $ref->[1]
$ref->[1]->[2] => $ref->[1][2]
Perl再入門 | アルパカ本に学ぶリファレンス入門5 ネストした配列リファレンス
無名配列を作る
my $ref;
{
my @array = (2, 4, 6);
$ref = \@array;
}
print "@$ref"; # 出力: 2 4 6
@arrayはブロックが終わったときに消滅しますが、$refはブロックが終わっても値を保持します。このとき、$refは、「名前の無い配列」への「リファレンス」を格納しています。
$refが参照している名前の無い配列を「無名配列」といいます。
($ref自体は「無名配列」への「リファレンス」です。)
値を取り出すときは、通常の配列リファレンスと同じようにデリファレンスします。
print $ref->[1]; # 出力 4
print "@$ref"; # 出力 2 4 6
無名配列へのリファレンスを作る
まず、通常の配列へのリファレンスを作る方法。my @array = ( 2, 4, 6 );
my $ref = \@array;
一時変数(@array)をいちいち作るのはめんどくさいので、下記のように書くこともできます。
my $ref = [ 2, 4, 6];
これを無名配列へのリファレンスといいます。内部的には、無名の配列 (2, 4, 6)を作って、その配列へのリァレンスを作っています。
一時変数がなくなり、コードが読みやすくなりました。
値を取り出すときは、通常の配列リファレンスと同じようにデリファレンスします。
print $ref->[1]; # 出力 4
print "@$ref"; # 出力 2 4 6
リファレンスからデータの実体を取り出すことを、デリファレンスするといいます。
まずは配列。
use strict;
my @list = ("a", "b", "c");
my $ref = \@list;
# 配列全体を取り出す
print "$ref\n"; # 出力: ARRAY(0x1829884)
print "@{$ref}\n"; # 出力: a b c
print "@$ref\n"; # 出力: a b c
# 配列の要素を取り出す
print "${$ref}[0]\n"; # 出力: a
print "$$ref[0]\n"; # 出力: a
print "$ref->[0]\n"; # 出力: a
ご欄のように、同じことをするのに書き方が何通りがあります。
リファレンス入門
Perl入門者がつまづきやすいリファレンスについて、続・初めてのPerl 改訂版(通称アルパカ本)リファレンスというのは、ある変数(データ)へのリンクあるいはショートカットのようなものです。
リンクとコンテンツの関係
例えば、今あなたのお気に入り(ブックマーク)にYahoo!Japanが登録されていたとします。このとき、実際にお気に入りフォルダに入っているものは、Yahoo!JapanのURL(リンク情報)だけであり、Yahoo!JapanのWebサイトのHTMLコンテンツそのものは格納されていません。
つまり、"http://www.yahoo.co.jp/" というURLは、Yahoo!Japanのサイトのトップページを指しますが、トップページのHTMLコンテンツそのものではありません。あくまでHTMLファイルが置かれている場所を示すアドレスにすぎないのです。
実例
さて、@list = ("a", "b", "c");
という配列があるとします。 この配列には3つのデータが格納されています。
ここで、\@listのように配列名の前に\を付けると(Windowsの場合は¥記号)、それは配列@listへのリファレンスを表します。
リファレンスはあくまで配列を指し示すものであって、配列そのものではありません。
リファレンスは、$変数に代入することができます。
$reference_to_list = \@list; # @listのアドレス(住所)を代入
$reference_to_list_2 = $reference_to_list; # これも、@listを指し示す。
$reference3_to_list3 = \@list; # これも@listを指し示す
この3つの$変数はどれも同じひとつの物(配列@list)を指しています。
なので、@listをの中身を書き換えると、これら3つの$変数が指し示すものも変わります。
これは例えば、
http://www.yahoo.co.jp
http://www.yahoo.co.jp/
http://www.yahoo.co.jp/index.htmlの3つのURLが指すものはどれも同じコンテンツ(ヤフーのトップページのhtmlファイル)であるのと似ています。ヤフーがトップページのコンテンツ(=index.htmlファイル)を書き換えると、これら3つのURLが返す結果が変わります。
リファレンス($reference_to_list)とデータ(@list)の関係もこれと同じことです。
ちなみにリファレンスをprint出力すると下記のような結果になります。
print $reference_to_list;
出力: ARRAY(0x1829884)この" ARRAY(0x1829884)" が、@listを指し示すアドレスです。@listはコンピュータのメモリ上に存在し、そのメモリ上のアドレスが" ARRAY(0x1829884)"なのです。
ちなみに、$reference_to_list2, $reference_to_list3をprint出力した場合も全く同じ結果が出ます。
forとforeachは、何が違うのか?
実は、違いはありません。
まったく同じです。
リャマ本こと「初めてのPerl」の第10章にもこう書いてあります。
Perl文法の中では、キーワードforeachはキーワードforと完全に等価です。
つまり、プログラムの中で、forと書いてもforeachと書いても、Perlはそれを同じものとして扱うのです。
したがって、下記の2つのループは同じ動作をします。
use strict;
use warnings;
my @array = ("x", "y","z");
foreach(@array){
print $_."\n";
}
for(@array){
print $_."\n";
}
で、どちらを使えばよいのかというと、
文字数が少ないFORをお勧めします!
(ダジャレではない)
関連記事
Perl再入門 | 超簡単!for,foreachの使い方 Perl再入門 | for,foreachはループ対象の配列を書き換えます。ご注意。配列に対してforやforeachでループ処理をする際に、制御変数の中身を変更すると、元の配列の中身も変更されてしまいます。
知らないと思わぬ損をするので、気をつけましょう。
私は今まで知りませんでした。(><)
use strict;
use warnings;
my @array = ("x", "y");
for (@array){
$_ = "z";
}
print "@array";
出力結果:z z
なお、以下のような書き方でも同じ結果になります。
for my $a (@array){
$a = "z";
}
関連記事
Perl再入門 | 超簡単!for,foreachの使い方forやforeachは、配列の全要素を対象としたループ処理をするときに使います。
use strict;
use warnings;
my @array = ("x", "y");
for(@array){
print "$_¥n";
}
出力結果:
x
y
※ forの代わりにforeachと書いても全く同じ動作をします。
関連記事
[Perl] -w とuse warnigs;の違いについて
Perl/CGIに必ず登場するuse strictの解説(初心者向け)