Unknown::Programming このページをアンテナに追加 RSSフィード

2007-06-26 一連

$_[0]の謎は偶然の産物

勘違いしてしまうのしょうがないね。


また、ワーク変数リファレンス値を代入後、デリファレンスすると元の値にアクセスが出来ます。

しかし、$_[0] を直接デリファレンスした $$_[0] では、元の値にアクセスが出来ません。

ワーク変数と$_[0]の中身は、同じリファレンスが入っているにも関わらず、そうなるのです(謎)。

Perlの関数引数 $_[0]の謎 - 燈明日記

元記事の現象とは下記のようなコードを書いた時の話ですが、


use strict;

sub hoge {
    print $$_[0];
}

my $str = 'aaa';
hoge(\$str);

これを実行してもprintで何も出力されないというわけですね。

実はこれ、謎でもなんでもなくて単にデリファレンスの優先順位が配列参照よりも低いから起こってるだけです。

つまり上記のコードは@_の0番目の要素をスカラデリファレンスしているのではなく$_を配列リファレンスとしてデリファレンスした0番目を参照していることになります。

ややこしいですね。

もしこれが@_じゃなくて普通の配列を使用していた場合はそもそもstrictに怒られます。


use strict;

my $str = 'aaa';
my @hoge = (\$str);

print $$hoge[0];

# Global symbol "$hoge" requires explicit package name

$hogeなんて変数宣言されてねーよ!!!!!!みたいな。

@_の場合は$_というグローバル変数がたまたま存在してるのでエラーにならないわけですね。

上記の例でも$hogeを予め宣言してたら当然エラーにはなりません。


use strict;

my $str = 'aaa';
my @hoge = (\$str);
my $hoge = ['bbb'];

print $$hoge[0]; # bbb と表示

では次にどうやって配列の要素をスカラデリファレンスするかというと、{}を使って優先順位を明示することです。


use strict;

my $str = 'aaa';
my @hoge = (\$str);

print ${ $hoge[0] }; # $hoge[0]を${}でデリファレンスする

これでわかったと思いますが、さっきまでの例は${ $hoge[0] }ではなく、${ $hoge }[0]と解釈されてたわけです。

デリファレンスはこういったややこしいこともあるのでデフォルトの動作に任せないほうがよいでしょう。

常に優先順位を明示するのがいいと思いますが、配列ハッシュ関数などのリファレンスの場合は{}ではなく->を使った方法で書くのが良いでしょう。


 my $array = [];
 my $hash  = {};
 my $code  = sub {};

 # わかりやすい
 print $array->[0];
 print $hash->{key};
 print $code->();

 # わかりにくい
 print ${$array}[0];
 print ${$hash}{key};
 print &{$code}();

この辺の話はPerlベストプラクティス(翻訳)p.245に書かれています。

11.1 逆参照(デリファレンス)

可能な限り、矢印を使って逆参照する

11.2 中かっこで囲まれた参照

プレフィックスによる逆参照以外に選択の余地がなければ、参照を中かっこで囲む

PBP万歳!ですね。

Perlベストプラクティス

Perlベストプラクティス

chaichanPaPachaichanPaPa 2007/06/28 21:36 はじめまして、燈明日記のchaichanpapaと申します。
お蔭様で、謎が解けました。ありがとうございました。
本ブログをいろいろと読ませてもらいました。
凄いPerlerから解説してもらえて光栄です。
fbisさんと同様に『必死こいて勉強しないと身につかない』と改めて思いました。これからも、ご指導よろしくお願い致します。

fbisfbis 2007/06/29 11:01 いえいえ、恐縮です。全然凄いPerlerじゃないですよ!まだまだ日々勉強中です^^;
必死こいてってのもありますが、結局は好きか嫌いかだと思います。Perl、楽しいし好きですね。だから身についたのかも。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証