3.6 foreach制御構文

配列を処理するには便利そうなforeach。
さすが文字列を処理するのが得意なPerlです。


実際に動くところを見たいので、
例題を書き写してみます。

#!/usr/bin/perl -w
use strict;

my $rock;
foreach $rock (qw/ bedrock slate lava /) {
 print "One rock is $rock.\n"; #3つの岩の名前を表示する。
}

とすれば、
One rock is bedrock.
One rock is slate.
One rock is lava.
と表示される。
ほうほう、なるほど。
配列の要素を全部処理し終えれば
ループを抜けるんですね。
配列の要素数を明示的に求めなくても
処理できるのは、便利ですね。


配列の勉強のために、
@hogeを使って同様の処理をする場合も
考えてみます。

#!/usr/bin/perl -w
use strict;

my @rocks = qw/ bedrock slate lava /;

foreach my $rock (@rocks) {
print "One rock is $rock.\n"; #3つの岩の名前を表示する。
}

foreachの中でmyで宣言するのが
マナーとしてよいのかどうかわかりませんが、
ワーニングも出ずに動きます。
なるほどねぇ。


と思ったら、直後にほぼ同じ例題がありました。
use strictを使っていないので、
宣言してませんが。
ついでにこれもやってみよう。

#!/usr/bin/perl -w
use strict;

my @rocks = qw/ bedrock slate lava /;

foreach my $rock (@rocks) {
 $rock = "\t$rock";
 $rock .= "\n";
}
print "The rocks are:\n", @rocks;

で、
The rocks are:
bedrock
slate
lave
となる。
制御変数をループ内で変更できるってことですね。


加えて、

  • 制御変数はループが終了すると、ループが開始する前の値に戻る。

んだそうです。
ってことは、上記のプログラムの末尾に
print "One rock is:\n", $rock;
なんて書いても、宣言されたのが制御変数としてなので、
コンパイルエラーになっちゃうよ、ってことですね。


試したら、確かにそうなりました。:-)

3.5 配列を文字列の中に展開する

ここで覚えたことのメモ。

  • ダブルクォート文字列の中にメールアドレスを入れると、配列として解釈されちゃうYO!!

そりゃそうですよね。
@があるもんね。
そういう時はシングルクォートでやる、と。

pop, push, shift, unshift

  • popは配列の最後尾の要素を取り出して、返す。
  • pushは配列の最後尾の要素に追加する。
  • shiftは配列の先頭の要素を取り出して、返す。
  • unshiftは配列の先頭の要素に追加する。

あぁ素敵。
配列処理としては便利な演算子たち。
これを回せば全ての要素を舐めることができるんですね。
Cだとインデクスをインクリメントして
舐めるところですが。


P55の脚注に、ジョークという言葉に紛らわせて
筆者の主張が力強く書かれています。

配列に対してインデクス(添え字付けする)を使うということは、Perlの良さを活用していないことになります。もし添え字付けの代わりにpop、push、および類似の演算子を使うと、あなたのコードは、たくさんの添え字付けをする場合に比べて、たいてい速くなります。さらに、「添え字が1つずれてしまった」という間違い---いわゆる「植え木算エラー(fencepost error)」---を避けることができます。しばしば、初心者のPerlプログラマが(Cに比べてPerlのスピードがどれくらいかを知ろうとして)、C言語向けに最適化されたソートアルゴリズム(添え字付けを大量に含むもの)を、Perl向けにそのまま(大量の添え字付けを含んだまま)書き換えて、「何でこんなに実行が遅いのでしょう?」と質問してくることがあります。それに対する答えは、「ストラディバリウスのバイオリンを使って、釘を打つのは良い工作法とは言えません」というものです。

後半の大袈裟な比喩にはニヤリとさせられますが、
それにしてもこれらの演算子の価値はあります。
ただし添え字付けを使わずにこれらの演算子だけで実行するには
不便も多いので、両方できるところに価値があるんでしょう。

3章 リストと配列

リストはデータであり、配列は変数である

なるほど。


ここで学んだことのメモ。

  • インデクスは0オリジン。
  • 最後の要素は$#hogeで指せる。

-負のインデクスは-1、-2、-3のみ。ただし実際に使うのは-1のみ。

  • リストリテラルは(1, 2, 3)で表現。
  • 範囲演算子..は、左右のスカラー値の間を1ずつ増加するリストを生成する。例えば(1..5)とすれば、(1, 2, 3, 4, 5)と書くのと一緒。
  • qw(quoted words またはquoted by whitespace)を使うと、シングルクォートの代わりに使える。
  • qwは、デリミタに任意の記号を使える。

範囲演算子っていいですね。
値が文字列だったらエラーが出るんでしょうか。


qwのデリミタが任意の記号というのは、
一瞬なんでろうな、と思ったけど、
この本にも書いてあるように
どんな記号の文字列も容易に扱えるように、
ってことなわけで、素晴しい仕様ですね。


それ以前の話ですが、スカラー変数と配列は、
全く同じ表記でOKなんですね。Perlでは。
数値と文字列が同じくらいビックリしました。
確かに何が代入されるか、とか、
使用される演算子が何か、で確定できますから、
これで何の問題もないんですよね。
なんて自由度が高いんだろう。Perlって。


と、読み進めたら、ちょっと違った。

  • 配列全体を指す場合は@hogeと書く。

なるほど、$hogeはやっぱり配列全体を
指すわけじゃないってことですね。


脚注に書いてある

Larryは、それぞれ$calar(scalar)と@rray(array)だから、ドル記号とアットマークを選んだ

っての、いいですね。
わかりやすくて。


このエントリは長くなりすぎたので
一旦休憩。旦~