Perlのちょっとしたメモ

くだらないメモ。


色々な否定

結果を " ! " で否定すると1か未定義値になる。

undef関数の戻り値の否定

1 になる。

print !undef , "";
スカラーの否定

0もしくは空文字列("")もしくは未定義値のときは1, それ以外は未定義値。

配列やハッシュの否定

要素が1つでもあるときは未定義値, ないときは1になる。
(ハッシュの場合はキーが1つでも存在する場合はundef。(= keys %hash == 0 が成り立つ))

リファレンス

定数となる数値や文字列をリファレンスで取った場合、参照先を書き換える事はできない。

$ref = \3.14;
print "\$ref: ", $ref , " : $$ref\n";
$$ref = 1.72; # 参照先の値を変えようとするとダメ
print "\$ref: ", $ref , " : $$ref\n";
$ref = \1.72; # これはok
print "\$ref: ", $ref , " : $$ref\n";


でも戻り値のリファレンスならば書き換えることができる。

$ref = \do{"ABC"};
print "\$ref: ", $ref , " : $$ref\n";
$$ref = 'DEFG';
print "\$ref: ", $ref , " : $$ref\n";


undefや実行結果のリファレンスも取ることができる。

$ref = \do{!1;};
$ref2 = \undef;
print "\$ref: ", $ref , "\n";
print "\$ref2: ", $ref2 , "\n";
print "\$ref == \$ref2 : ", $ref == $ref2 , "\n"; # 未定義値同士なのでtrue
print "\$\$ref == \$\$ref2 : ", $$ref == $$ref2 , "\n"; # しかし参照先は違う

戻り値でのundefな値とundef関数で返ってくる値の参照先は異なる。


また、\do{!1;};などの実行結果の参照先も毎回異なる。
参照が取れるってことはあらゆる戻り値はメモリ上に1度格納されていることになる?
戻り値をリファレンスで返せば、アドレスのコピーだけになるので、場合によっては早くなるのでは、と予想。


ある実行結果からデータを受け取り、それを代入する処理を100回行い、1000回実行して平均を見る。
case 1: 実行結果のデータをそのままコピー。
case 2: 実行結果のデータのリファレンスを受け取り、リファレンスから参照してコピー

use Benchmark;

my $str = ('A' x (1024*1)); # コピーするデータサイズ

timethese(1000, {case1 => \&case1, case2=> \&case2,});

sub case1{
	for(1..100){
		my $x = do{ $str; };
	}
}

sub case2{
	for(1..100){
		my $rx = do{ \$str; };
		my $x = $$rx;
	}
}


上を3回行った平均。
左の値はデータの大きさ(単位:byte. 1024*10=10KByte)。
右の値は1秒当たりに処理できる回数。
1024と1024*10の時だけ、試行回数を10000回に増やした。

case 1
1024     : 40853 回/s
1024*10  : 7273.67 回/s
1024*100 : 472.89 回/s
1024*1024: 49.63 回/s

case 2
1024     : 23420 回/s
1024*10  : 7272.33 回/s
1024*100 : 491.09 回/s
1024*1024: 43.95 回/s

1024*100 のときだけ若干case2が上回ったが、それ以外はcase1以下だった。
リファレンスの生成のコストが割とかかっている模様。特に、1024の時の差はすごいものがある。
100KByteあたりのデータを戻り値として受け取る時はリファレンスで受け取ったほうが早いようだ。
しかし、データ量が増えるにつれ、case2は劣り始めるようだが、
ここまでくると、メモリ領域の確保のコストのほうがかかっている気がしないでもない。


おまけ。
undef関数の戻り値の参照先は何度やっても同じっぽい。
既に未定義値を定数として用意してあってそれを返しているとか?

$ref2 = \undef;
print "\$ref2: ", $ref2 , " : $$ref2\n";
$ref2 = \undef;
print "\$ref2: ", $ref2 , " : $$ref2\n";
$ref2 = \undef;
print "\$ref2: ", $ref2 , " : $$ref2\n";
$ref2 = \undef;
print "\$ref2: ", $ref2 , " : $$ref2\n";