# perl リファレンスは簡単 {{tag: 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 変数の深遠を探りたいなら、{{cpan: 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!!