2015/10/08

#perl リファレンスの作り方

my $r = [@list];my $r = \@list; は、同じようにリファレンスを取るが、前者は一回リスト展開して新しいリストのリファレンスを返してるぜーという話。

$ perl -le 'my @list=(1,2,3); print [@list] for (1..3); print \@list for (1..3);'
ARRAY(0x2292f40)
ARRAY(0x229cb98)
ARRAY(0x229cb80)
ARRAY(0x2292df0)
ARRAY(0x2292df0)
ARRAY(0x2292df0)

\@list は何回リファレンスをとっても同じ(そりゃそうだ)。

展開してコピーされてるので元のリストは書き換わらない。

$ perl -le 'my @list = (1..10); my $r = [@list]; $r->[0] = 100; print $list[0];'
1

いわゆるリファレンスだとこう。

$ perl -le 'my @list = (1..10); my $r = \@list; $r->[0] = 100; print $list[0];'
100

なので展開する方は遅い。

#!/usr/bin/env perl
use strict;
use warnings;
use Benchmarks sub {

    my @ARRAY = (1..100);

    return +{
        ref => sub {
            my $r = [@ARRAY];
        },
        bs => sub {
            my $r = \@ARRAY;
        },
    };
};

結果。

Benchmark: running bs, ref for at least 1 CPU seconds...
        bs: 1.32497 wallclock secs ( 1.32 usr +  0.00 sys =  1.32 CPU) @ 6950787.12/s (n=9175039)
       ref: 1.03553 wallclock secs ( 1.04 usr +  0.00 sys =  1.04 CPU) @ 167232.69/s (n=173922)
         Rate   ref    bs
ref  167233/s    --  -98%
bs  6950787/s 4056%    --

いわゆるリファレンス欲しいだけなのにうっかり展開してるとマイナスでかい。

ハッシュも +{%hash} とかより \%hash

もちろん、コピーした新しい値のリファレンスが欲しい場合はそれはそれで OK

サイト内検索