Translate

2008年7月13日日曜日

リファレンスの復習

なんだかうろ覚えなとこがあったんで
復習の意味を込めてメモ書きしておきます。

スカラーの場合。
use strict;
use wanings;

#set
my $scalar = "スカラー"; #スカラーのファニー文字は$

#リファレンス
my $ref_scalar = \$scalar; #リファレンスを取得するには\をつける

#表示
print "$ref_scalar\n"; #リファレンスを表示してみる

print "${$ref_scalar}\n"; #デリファレンスしてから表示

結果

・ひとまずまとめ。
変数や値のリファレンスを取得したい場合はそれぞれに \をつければOK
リファレンスから元の対象を参照(デリファレンス)するには、参照先の変数が
使用しているファニー文字(変数の頭につける$とか@とか)をつけるとOK
デリファレンスの書き方は、ブラケットを取り外し$$ref_scalarと書くこともOKだが…
可読性を考えると${$ref_scalara}の方がよい。


配列とハッシュの場合。
use strict;
use warnings;

#set
my @array = qw(array1 array2 array3);
my %hash = (guu => "rock",
cyoki => "scissors",
paa => "paper",
);

#リファレンス
my $ref_array = \@array;
my $ref_hash = \%hash;

#表示
print "@{$ref_array}\n";
print "%{$ref_hash}\n";

結果


さきほど、ファニー文字つけりゃリファレンス元の値を表示できると
書いてしまいましたが、配列の方は、各要素が表示されているけども
ハッシュの方は何か変ですね…
これって、
%{$ref_hash}%{リファレンス}を表示しているだけですね 汗

そもそも
print "@array\n";
で変数展開されても
print "%hash\n";
じゃ、変数展開されませんからねぇ
当然と言えば当然な挙動ですね 笑
use strict;
use warnings;

my @array = qw(array1 array2 array3);
my %hash = (guu => "rock",
cyoki => "scissors",
paa => "paper",
);
print "@array\n";
print "%hash\n";

結果


どうでもよい話ですが…
print @array, "\n";
print %hash, "\n";
とすると
array1array2array3
paarockcyokiscissorsguurock
と展開されます。。



さて横道へそれるのはここまでとして配列とハッシュの各要素を表示してみます。
use strict;
use warnings;

#set
my @array = qw(array1 array2 array3);
my %hash = (guu => "rock",
cyoki => "scissors",
paa => "paper",
);

#リファレンス
my $ref_array = \@array;
my $ref_hash = \%hash;

#表示
print "${$ref_array}[0], ${$ref_array}[1], ${$ref_array}[2]\n";
print "${$ref_hash}{guu}, ${$ref_hash}{cyoki}, ${$ref_hash}{paa}\n";

結果


配列、ハッシュ、サブルーチンは、アロー演算子を使って簡略化して表記できます。
書き方は、下記の通り。
リファレンス->[要素] 配列
リファレンス->{要素} ハッシュ
リファレンス->(引数)  サブルーチン

つまり
${$ref_array}[0]   → $ref_array->[0]
${$ref_hash}{guu} →  $ref_hash->{guu}
と書くことができる。
これって、多次元配列をデリファレンスする時に便利よいのねぇ。


ということで、次は多次元配列でも。
@number = ((1, 2, 3),
(4, 5, 6),
(7, 8, 9),
);
としたところで、多次元配列にならない。
平坦化してしまうので上の表記は、
@number = (1, 2, 3, 4, 5, 6, 7, 8, 9);
と同じことである。
多次元配列を実現したい場合は、
@row1 = (1, 2, 3);
@row2 = (4, 5, 6);
@row3 = (7, 8, 9);

@cols = (\@row1, \@row2, \@row3);

$number = \@cols;

としてあげるとOK
たとえば、4を表示するには…
${$number}[1] と書くと \@row2 というリファレンスを表している。
目的の4は、\@row2の第1要素なので…
${${$number}[1]}[0] となる。
非常にわかりづらい…
じゃ、アロー演算子を使ってもう一度考えてみる。
配列でアロー演算子を使うには
リファレンス->[要素] で表現できるので…

${$number}[1] は、 $number->[1]と表記できる
$number->[1]はリファレンスで4は、\@row2の第1要素なので
${$number->[1]}[0]となる。
${$number->[1]}[0] は、 $number->[1]->[0]と表記できる。

ちなみに、アロー演算子は ]->[  や }->{ といった風に
(角括弧|ブラケット)の間にある場合省略することができる。

というわけで、
$number->[1]->[0] は、 $number->[1][0]と表記できる。
最初に記した
${${$number}[1]}[0] と比較すると
$number->[1][0]    の方がわかりよいですよねぇ。


で、ここであることに気づきます。
せっかく、row1,row2,row3,colsという配列を作ってみたものの
最終的に各要素にアクセスするのに$number->[1][0]で済んで
しまい、せっかく悩んでつけた変数名が入ってません。
そんなわけで、無名配列を使えば変数名を使わずに同様のことができます。

配列やハッシュで値を代入する際に
@array = (1, 2, 3);
%hash = (a=>1, b=>2, c=>3);
のように括弧でくくります。
無名配列や無名ハッシュを作る場合は、
配列は[]でくくり、ハッシュは{}でくくります。
それぞれの要素にアクセスする際に何でくくるかを思い出すとよいですよね。

つまり、さきほどのrow1, row2, row3, colsを使わないで表現すると
$number = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
と表現できます。
無名配列や無名ハッシュは、"無名"なんで何かの変数に入れないと使えません。
そして、代入しているものは、実際の値ではなくリファレンスです。


次は、サブルーチンです。
use strict;
use warnings;

#set
sub csrf{ #引数を取らない場合
print "こんにちはこんにちは!\n";
}
sub message{ #引数を取る場合
my $str = shift;
print "$str\n";
}

#リファレンス
my $ref_csrf = \&csrf;
my $ref_message = \&message;

#サブルーチンを実行
&{$ref_csrf};
&{$ref_message}('今日の更新は長い…');

結果


さきほど、アロー演算子の説明の時、下記のように書きました。
リファレンス->[要素] 配列
リファレンス->{要素} ハッシュ
リファレンス->(引数)  サブルーチン

つまり、
&{$ref_message}('今日の更新は長い…');
 は、
$ref_message->('今日の更新は長い…');  と書くことができます。

ちなみに、このエントリーの最初の方でリファレンスを取得するには
変数や値に\をつければOKと書きました。

つまり、
$ref_message->('今日の更新は長い'); は、
$ref_message->(\'今日の更新は長い'); と書くことができます。

そうなると、サブルーチン内で受け取る$strはリファレンスということになるので
print関数内はデリファレンスしなければいけません。

use warnings;

#set
sub message{
my $str = shift; #$strの中身は、リファレンス
print "${$str}\n";
}

#リファレンス
my $ref_message = \&message;

#サブルーチンを実行
$ref_message->(\'今日の更新は長い…');


最後に、無名サブルーチンです。
無名(配列|ハッシュ)と一緒ですね。
my $csrf = sub {print "こんにちはこんにちは!"};
&{$csrf};
でOKですね。
無名サブルーチンは、クロージャあたりで使うらしいですよ。

0 件のコメント: