SlideShare a Scribd company logo
変数、リファレンス February 19, 2011 Hokkaido.pm #4 Kenichi Ishigaki (charsbar)
始める前に…
Perl の変数なんて 別にむずかしくないよね という方?
『言語設計者たちが考えること』
Larry がこんなことを 言っていました
「自然言語の原理を コンピュータ言語へと 組み込む最善の 方法を探求」
Perl はもともと C 、 sed 、 awk 、 sh の よいとこどりをした言語
英語っぽさを 感じることもあります
たとえば 英語の名詞
無冠詞 : pen 単数 : a pen 複数 : pens
無冠詞   (pen)   「~というもの」
そのままでは 数えられないもの   #  または数えないもの
辞書の見出し語   固有名詞 抽象名詞
Perl の場合
foo   裸のワード #  英数字と下線だけからなる単語
昔はよくこんな使い方を していたものです   open FOO, 'bar';
定数を定義するときにも よく使われています   use constant PI => 3.14; print PI * 2; # 6.28
具体的なものの 代入は不可   foo = 'bar'; #  エラー
具体的なものを 扱うにはどうするか
そのものが 単数か複数かで 変わります
単数の場合
英語では冠詞を つけるのでした   pen  ->  a pen
Perl の場合は 「 $ 」という記号を つけます   foo  ->  $foo
この記号は あくまでも 冠詞扱い   #  変数名の一部ではありません
だからこんな 書き方も可能です   $ foo = 1; print $ foo; # 1
真似しないで くださいね
どうして $ なのか
スカラー (scalar) の 頭文字   #  高校の物理で習いましたよね #  「矢印」がつかない値
複数の場合
英語では語形が 変わったり   a pen  ->  pens a man  ->  men
数をあらわす 形容詞句がついたり   two pens a lot of men
単複同型というのも ありました   単数 : a sheep 複数 : sheep
Perl の場合は @ という 記号をつけます   @foo = (1, 2, 3);
配列 (array) の 頭文字から perldata では「 these とか those 」
細かくいうと 配列とリストは別物
$foo と @foo の関係
名前は同じです
いっぺんに扱う 手段もあります
中身は別物です   a pen  ≠  pens
「複数」の性質
単数+単数=複数   @pens = ($red_pen, $blue_pen);
複数+複数=複数   @pens = (@red_pens, @blue_pens);
要素の個数は あまり気にしません   #  複数は複数です
配列の要素を 扱うときは for などで   foreach (@pens){ print $_ }   # $_ は英語の it と同じ単数の代名詞 #  中身については空気を読んで
コアレベルでは 省略できることも多い   foreach (@pens) { print } print for @pens;
他動詞だから目的語をとるはず、というのが 暗黙の了解
誤解を避けたければ 明示して   for $pen (@pens) { print $pen }
処理の順番は?
リストの場合は左から右 ということになっています   print for (1, 2, 3);
でも、左ってどこ?   print for @pens;
どこかにはあるはずです が、隠れています
という記号をつけると 起点の位置を 取得できます   pens;
具体的にどこにあるかは 気にしなくていいです
@ という具体的な 文脈をあらわす記号を 打ち消しているイメージ
起点がわかったら 向きと長さを指定すれば 個々の要素に アクセスできます   (pens)->[0];
この起点のことを Perl の文脈では リファレンスと呼びます
「よく使われる表現は、 あまり使われない表現 よりも短くあるべき」 ( 『言語設計者たちが考えること』 )
ふだんはもう少し 楽をしたいですよね
ひと頃は こんな風にも 書けました   @pens->[0];
Perl 5.8 で 廃止されました   # 文脈がわかりづらくなるから #  複数のものから矢印 ?!
起点はひとつしか ありません
ということは 単数扱いに なるはずです
Perl 5 では スカラーとしても 扱えるようになりました   $pens_ref = pens; $pens_ref->[0];
矢印が生えるのに !?
普通のスカラーとは 違います
中身を覗いて みましょう   perl -e "print array"   # ARRAY(0x33e288)
ぐちゃぐちゃに ならないよう 内部的には別扱い されています
Devel::Peek を使うと 詳しく調べられます   perl -MDevel::Peek -e  "@a = (1, 2); print Dump(a)" # Perl 5.6 以降はコアに入っています
むずかしいことは 忘れてください
矢印が生えていれば (たいていは) リファレンスです   $pens_ref->[0];
ref でも確認できます   ref $scalar_or_ref ? 'ref' : 'scalar';
誤解されそうな文脈では 名前を変えておきましょう   ○   $pens_ref = pens; ×  $pens  = pens;
これでだいぶきれいに 書けるようになりました
でも、もう少し 楽をしたいです
できるように なっています   @pens;  #  $pens_ref = pens; $pens[0]; #  $pens_ref->[0];
$pens と $pens[0] と $pens->[0] は それぞれ文脈が 異なります
$pens は純然たるスカラー(たぶん)   $pens->[0] の $pens はリファレンス   $pens[0] は @pens の一要素
ベクトルの指す値は 矢印ひとつにつき ひとつのみです   $array_ref->[0]   #  返り値はひとつのはずです
配列にはスカラー (として扱えるもの) しか入れられない という制約が   $array_ref->[0] にわざわざ $ をつける必要はありません
配列から複数の値を 取り出したい場合も あります
ひとつひとつ列挙 してもかまいません   $first_pen  = $pens[0]; $second_pen = $pens[1];   #  冗長ですよね
一行にまとめてみました   ($first_pen, $second_pen) = ($pens[0], $pens[1]);
もう少し短くできます   ($first_pen, $second_pen) = @pens; # 3 つめ以降の pen は無視されます
こんな書き方も できるのですが…   @two_pens = @pens[0, 1];  # @pens[0..1]
必要がなければ 避けた方が無難
意図とは異なる (かもしれない) 結果になるもの
1 本なのに 複数扱い !? ×  @pens[0];
ベクトルの行き先はひとつのみです ×  $pens_ref->[0, 1]
先にデリファレンスされて しまいますので… ×  @$pens_ref->[0, 1]
配列にしてからなら OK ○  @$pens_ref[0, 1]
便利に使える 場合もあります
複数の配列を含む 配列の場合
赤だけ、青だけの 配列を区別できません   @pens = (@red_pens, @blue_pens); ×  (@red_pens, @blue_pens) = @pens;
配列に入れられるのは スカラー扱いできる値のみ     配列をそのまま配列に 入れることはできません
区別するには リファレンスを 使います   @pens = (red_pens, blue_pens);
矢印をたどっていけば 目的地につきます   ($red_pens_ref, $blue_pens_ref) = @pens; $red_pen  = $red_pens_ref->[0]; $blue_pen = $pens[1]->[0]; # = $pens[1][0];
配列のなかの リファレンスから 生える矢印はふつう省略できます
自動的にふられる 番号ではわかりづらい場合もあります   @pens = (red_pens, blue_pens);
青ペンの 1 本目 には見えません ! $pens[1][0];
要素が増減したら いちいち順番を直す必要があります
もっと明確に書きたいときは ハッシュという特殊な配列を使います   #  昔は連想配列と言っていました
ハッシュの場合は 届け先を明記します %pens = (   red_pens  => red_pens,   blue_pens => blue_pens, );
%  ->  c/o   ->  care of  「~様方」
使い方は ふつうの配列と よく似ています
%pens = (...); $pens{red_pens}; $ pens {blue_pens};
$pens_ref = pens; $pens_ref->{red_pens}; $ pens_ref -> {blue_pens};
それぞれの要素に アクセスしたいとき   for (keys %hash){ print $hash{$_} } for (values %hash){ print $_ } while(($key, $value) = each %hash) { ... } #  並び順は不定です
%pens = (   red_pens  => red_pens,   blue_pens => blue_pens, ); ハッシュのなかの 配列に名前は必要?
%pens = (   red_pens  => ['mine', 'yours'], # red_pens   blue_pens => ['his', 'hers'],  # blue_pens ); $red_pens_ref = $pens{red_pens};  必要なければ 省略してしまいましょう
[...] は無名配列の リファレンスです     ...) だと別の意味になるので要注意
ふつうの配列に したいときは 「冠詞」をつけて   @pens = @{['red_pen', 'blue_pen']};
もちろん 無名ハッシュへの リファレンスも つくれます   $pens_ref = { red_pens => 2, blue_pens => 3 }; %pens = %{{red_pen => 1, blue_pen => 2}};
どうして @{...} に なるのでしょう?
Perl にはシンボル テーブルと呼ばれる 特殊なハッシュが 用意されています
中身を覗いて みましょう perl -MDevel::Symdump –e  "print Devel::Symdump->rnew->as_string"
もう少し詳しく 見たいときはこちら   perl -MData::Dump=dump  -e "print dump(%::)"
グローバル変数 パッケージ 関数/メソッド
多くのものがこの 無名ハッシュのなかに 登録されています
$bl{HASH}{"Data::"}{HASH}{"Dump::"}{HASH}{"seen"} = {   "16258dc" => ["k", []],   "16258e8" => ["bl", ["*{HASH}"]],   "1625900" => ["bl", []],   "1625918" => ["al", []], } 変数名やリファレンスの ID は ハッシュのキーになっています
これまで見た変数は このようにも 書き換えられます
print ${foo};  # $foo print @{"bar"};  # @bar print ${ 'b' . 'az' }{foo}; # $baz{foo}
文字列のなかに 変数を埋め込むときに便利なことも     $foo = "chars"; print "${foo}bar";
デリファレンスの 優先順位を明示したいときにも有効
全部ひっくるめた 型グロブというものも あります   *{"foo"}
昔はファイルハンドルの 受け渡しなどに 使っていました
いまはシンボルテーブルを いじるときにしか使いません
型グロブは 「無冠詞」の変数も うまくさばいてくれます   open FOO, ‘file’; do_something(*FOO);  # Perl 4 風
ゆるい世界では こんな書き方さえ できます
@array = (1, 2); print  array->[0]; #  警告つき print *array->[0]; #  警告すらでません
今日はあえて ゆるい世界の話に 終始しました   今日取り上げた例のいくつかは、 use strict; するとエラーになります
後付けの説明なので 実際の歴史や実装とも ずれがあります
Perl 自体、当初の デザインからは さまざまな点で 変わってきています
そのすべてを覚えて いられる人は おそらくいません
詳しいことを 知りたい人は perldoc.jp へ
perldata, perldsc, perlref, perlreftut, perlobj, perllol, perlsub, perlfaq4, perlfaq7
ご静聴ありがとう ございました

More Related Content

変数、リファレンス