perl リファレンスは簡単
新年度ですね!!
サンプルコードは間違ってるかもしれないから、適当にワンライナーにでもして試してね!!!
ただのハッシュのコピー
まず、リファレンスでないハッシュだと "値" がコピーされるのを実行します!
# ただのハッシュですね!
my %foo = ( key => 1 );
# コピーしてみますよ!
my %bar = %foo;
# コピーした先で値を代入してみますよ!
$bar{key} = 2;
# おおもとの方は書き換わってませんね!あたりまえですね!
print $foo{key}; # 1
リファレンス
こういうのがリファレンス
HASH
my $foo = { key => 1 };
print ref($foo);
ARRAY
my $bar = [1, 2, 3, 4];
print ref($bar);
SCALAR
my $baz = 123;
my $hoge = \$baz;
print ref($hoge);
ref 関数でなく、直接変数を参照すると、どれも中身はアドレスが入ってる。値がメモリのどこにあるかの情報を持ってるだけってことですね!
my $foo = { key => 1 };
print $foo; # HASH(0x8f1cc28)
リファレンスは "参照" それ自体がコピーされるのです!
# ハッシュリファレンスですね!
my $foo = { key => 1 };
# コピーしてみますよ!
my $bar = $foo;
# コピーした方で値を代入してみますよ!
$bar->{key} = 2;
# おおもとの方も書き換わってますね!
print $foo->{key}; # 2
リストのリファレンス
もちろん、リストのリファレンスでも同じ!!
my $foo = ['foo', 'bar', 'baz'];
# コピーしてみますよ!
my $bar = $foo;
# コピーした先($bar)で値を代入してみますよ!
$bar->[0] = 'hoge';
# おおもと($foo)の方も書き換わってますね!
print "$_\t" for @{$foo}; # hoge bar baz
デリファレンスしてコピー
デリファレンスしてハッシュにコピーすれば "値" がコピーされますよ!
# ハッシュリファレンスですね!
my $foo = { key => 1 };
# デリファレンスしてコピー
my %bar = %{$foo};
# コピーした先で値を代入してみますよ!
$bar{key} = 2;
# 書き換わるわけありませんね!
print $foo->{key}; # 1
ちなみに、デリファレンスしてリファレンスにしても "参照" のままっぽ!!
my $foo = { key => 1 };
# デリファレンスしてリファレンスにしてコピー
my $bar = \%{$foo};
# コピーした先で値を代入してみますよ!
$bar->{key} = 2;
# おおもと書き換わるわってますね!
print $foo->{key}; # 1
サブルーチンにリファレンス渡し
リファレンスわたして書き換えると呼びもとの方ももちろん変わる。(破壊的!!)
sub foo {
my $ref = shift;
$ref->{key} = 2;
return $ref->{key};
}
my $bar = { key => 1 };
foo($bar);
print $bar->{key}; # 2
書き換えるなら値を取り出してやるとかする!!
sub foo {
my $ref = shift;
my $key = $ref->{key}; # 値を取り出す
$key = 2;
return $key;
}
my $bar = { key => 1 };
foo($bar);
print $bar->{key}; # 1
コピーと参照の benchmark
取り急ぎ、リファレンス渡しは、値をコピーしないから超絶かわいい。
Benchmark: timing 5000 iterations of HASH, REF...
HASH: 6 wallclock secs ( 6.24 usr + 0.00 sys = 6.24 CPU) @ 801.28/s (n=5000)
REF: 0 wallclock secs ( 0.00 usr + 0.00 sys = 0.00 CPU)
(warning: too few iterations for a reliable count)
Rate HASH REF
HASH 801/s -- -100%
REF 5000000000000000000/s 624000000000000000% --
そーす。
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw/timethese cmpthese/;
my %HASH;
for (1..5000) { $HASH{$_} = $_; }
my $result = timethese (5000, {
'HASH' => sub { _hoge( %HASH ); },
'REF' => sub { _hoge( \%HASH ); },
});
cmpthese $result;
sub _hoge {}
perl 変数をみる
リファレンスに限らず、perl 変数の深遠を探りたいなら、Devel::Peek で覗くとOK。
$ perl -MDevel::Peek -le 'my $foo = { key => 1 }; print Dump($foo);'
SV = RV(0x8180918) at 0x8158cdc
REFCNT = 1
FLAGS = (PADBUSY,PADMY,ROK)
RV = 0x8158c28
SV = PVHV(0x815d190) at 0x8158c28
REFCNT = 1
FLAGS = (SHAREKEYS)
IV = 1
NV = 0
ARRAY = 0x81752b8 (0:7, 1:1)
hash quality = 100.0%
KEYS = 1
FILL = 1
MAX = 7
RITER = -1
EITER = 0x0
Elt "key" HASH = 0xe9806307
SV = IV(0x8174174) at 0x8158d54
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 1
注目はこのへん。
ARRAY = 0x81752b8 (0:7, 1:1)
hash quality = 100.0%
ハッシュは内部では ARRAY で quality 管理されてんのか!! とか興味深いですけど、うかつに each 使ったりしない限りここらを見ることは二度とないでしょう!! でも、unicode 的なあれで FLAGS を見ることもできて便利です!!
Let's enjoy Perl World together!!