代入文の返り値

昨日の日記で「リスト代入」について調べましたが、そういえば「代入文」自体の「返り値」について勉強するのを忘れていました。
Perl の代入文は、代入を行なった後の「左辺」を返します。
例えば、以下のような時に便利です。

use strict;
 
my ($x, $y, $z);
$x = $y = $z = 1234;
 
print "$x $y $z\n";

代入文に注目。代入文がつながっていますね。これは、代入文を返り値をさらに他の代入文の右辺にしているのです。
この実行結果は以下の通り。

1234 1234 1234

$x、$y、$z という3つの変数を一気に 1234 で初期化していますね。(^_^)
少し詳しく説明すると、代入演算子「=」は右結合(右から実行)なので、この代入文は、

$x = ($y = ($z = 1234));

という順番で実行されます。これは

$z = 1234;
$y = $z;
$x = $y;

と書いたのと全く等価です。


では、ここで問題です。以下のコードを実行すると、何が表示されるでしょうか。

use strict;
 
my $x;
(($x = 123) = 456) = 789;
 
print "$x\n";

もちろん、エラーにはなりません。(^_^)
ヒントは、「代入文は左辺を返す」「カッコで左の代入文から実行される」です。(もうほとんど答えですね(^_^;)


正解は以下の通り。

789

そうなんです。「代入文は左辺を返す」ので、「$x = 123」という代入文の返り値は「123」が代入された「$x」なのです。よって、返ってきた「$x」に対して、さらに代入する事ができます。
つまり上のコードの代入文は以下と同じ意味です。

$x = 123;
$x = 456;
$x = 789;

最終的な $x の中身は「789」になるわけですね。(^_^)


この「左辺値を返す代入文」というのは、Perl特有のものだと思います。少なくとも、僕が勉強した事のある言語ではこんな事はできません。
他にも、この性質をこのように利用できます。

chop($new = $old)

組み込み関数 chop は、受け取った変数の最後の文字を削除します。変数を直接操作するので、引数に渡せるのは「有効な左辺値」のみです。
つまり、$old の値を $new に代入してから、そのまま chop($new) している事になります。

$new = $old;
chop($new);

と等価ですね。
chop に限らず「新しいコピーを作ってから、そのコピーに対して操作を行なう」際に、この書き方がよく使われるそうです。覚えておいたほうがよさそうです。(^_^)