第53回 型グロブ
blessは2引数で - 北海道苫小牧市出身の初老PGが書くブログ
このようなご指摘をいただいていた。
正直なところ、
*new = \&Human::new;
の部分のアスタリスクは「型ブログ」と呼ばれるものであろうということぐらいの認識しかなく理解していなかった、そんな中、
Web::Scraper - Web Scraping Toolkit inspired by Scrapi - metacpan.org
のソースを、ひょんなことから読んでみようとおもって読んでみると、
同じように、
*
を使っているところがあった。
どうしようもなくわからないので、友人にきいたところ、
自前で import をしているのでは? といわれ、調べてみることに。
型グロブ
Perlでは頭に、
$ @ % &
という文字を付けてスカラー変数や、配列であることを示す。
これはファニー文字と呼ばれている。
ファニー文字があるので、
$c @c %c sub c{}
は別物であるとPerlは認識できる。
ただ、Perlは内部でこれらをひとまとまりとして管理している(多少噓)
ひとまとまりで管理したものを表すのが、
*c
である。 ファニー文字が書かれてあるところを*にすればよいのだ。
これが型グロブと呼ばれるものである。
なお、この型グロブはパッケージごとに別々にもっている。
http://www.geocities.jp/ky_webid/perl5/036.html
を参考に、mainパッケージがもっているものを表示してみる。
package Hoge; package main; use Data::Dumper; print Dumper \%main::;
結果:
$VAR1 = { '/' => *{'::/'}, 'stderr' => *::stderr, 'SIG' => *::SIG, 'utf8::' => *{'::utf8::'}, '1' => *{'::1'}, '"' => *{'::"'}, 'ARNING_BITS' => *{'::ARNING_BITS'}, 'CORE::' => *{'::CORE::'}, 'DynaLoader::' => *{'::DynaLoader::'}, '_<DynaLoader.c' => *{'::_<DynaLoader.c'}, 'stdout' => *::stdout, 'attributes::' => *{'::attributes::'}, '' => *{'::'}, 'stdin' => *::stdin, 'ARGV' => *::ARGV, 'INC' => *::INC, 'Scalar::' => *{'::Scalar::'}, 'ENV' => *::ENV, 'Regexp::' => *{'::Regexp::'}, '_</System/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/Data/Dumper/Dumper.bundle' => *{'::_</System/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/Data/Dumper/Dumper.bundle'}, 'XSLoader::' => *{'::XSLoader::'}, 'UNIVERSAL::' => *{'::UNIVERSAL::'}, 'overload::' => *{'::overload::'}, '$' => *{'::$'}, '_<perlio.c' => *{'::_<perlio.c'}, 'B::' => *{'::B::'}, 'main::' => *{'::main::'}, 'Carp::' => *{'::Carp::'}, 'Data::' => *{'::Data::'}, '-' => *{'::-'}, '_<perlmain.c' => *{'::_<perlmain.c'}, 'PerlIO::' => *{'::PerlIO::'}, '_<universal.c' => *{'::_<universal.c'}, '0' => *{'::0'}, 'BEGIN' => *::BEGIN, ' => *{':'}, '@' => *{'::@'}, '_<xsutils.c' => *{'::_<xsutils.c'}, '!' => *{'::!'}, 'STDOUT' => *::STDOUT, 'IO::' => *{'::IO::'}, '' => *{'::'}, '' => *{'::'}, '_' => *::_, '+' => *{'::+'}, 'Dumper' => *::Dumper, 'Exporter::' => *{'::Exporter::'}, '_<Dumper.c' => *{'::_<Dumper.c'}, 'bytes::' => *{'::bytes::'}, 'STDERR' => *::STDERR, 'Internals::' => *{'::Internals::'}, 'STDIN' => *::STDIN, 'warnings::' => *{'::warnings::'}, 'Config::' => *{'::Config::'}, 'DB::' => *{'::DB::'}, '<none>::' => *{'::<none>::'}, 'Hoge::' => *{'::Hoge::'} };
このようにmainパッケージは我々の知らないところで色んなものをもっているのだ。
こんどは、Hogeパッケージの方を表示してみる。
package Hoge; package main; use Data::Dumper; print Dumper \%Hoge::;
結果:
$VAR1 = {};
なにも表示されなかったので、
Hogeパッケージに hというサブルーチンを作ってみる。
package Hoge; sub h{}; package main; use Data::Dumper; print Dumper \%Hoge::;
結果:
$VAR1 = { 'h' => *Hoge::h };
このようにHogeパッケージが持っているものが増えた。
型グロブに代入する
さて、型グロブに代入する方法をみてみる。
型グロブに代入するには、リファレンスを代入してやればよい。
*c = [1,2,3]; *c = sub { print '型グロブ', "\n" }; print "@c", "\n"; c();
このようにリファレンスを代入すれば、
普通にファニー文字を使って値を取り出すことができる。
これはデリファレンスではなくて、型グロブとはそもそもリファレンスが指し示している場所を管理しているので、それにならってリファレンスを代入しただけである。
この型グロブを使えば、関数の名前を変えることができる。
正確には、関数のエイリアスを作れるようになる。
エイリアスとは、
第6回 エイリアスという発想と破壊的!という考え方 - bingo_nakanishiの他言語出身者のためのPerl入門
↑ここで紹介しあるものである。単に別名が付いただけで、そいつ自身なのだ。
関数のエイリアス作成
sub h { print '型グロブ', "\n" }; *f = \&h; f();
結果:
型グロブ
このようにすれば、関数のエイリアスを作成できる。
みての通り、f()を実行したのに関わらず、h()を実行したかのようである。
だから、次のようにすれば、
package Hoge; sub h { print 'Hogeのh', "\n" }; package main; *f = \&Hoge::h; f();
結果:
Hogeのh
他のパッケージの関数を呼べるのである。
だが、今の私では、
Web::Scraper - Web Scraping Toolkit inspired by Scrapi - metacpan.org
で使われている goto の箇所がよくわからない。
goto ラベル
ように使えるようであるが、なんのために使われているのかがよくわからない。
ファイルハンドルと型ブログ
その昔ファイルのopenは、
open FH, '<hoge.txt';
というように書かれていた。
FHと特にファニー文字を何もつけないファイルハンドルが使われていたのだ、
これが今使われていない理由は、このように作られたファイルハンドルはグローバルになってしまうからだ。
とまあ、それはおいておいて、このファイルハンドルと一緒によく語られていたのだが、
*FH
というようにファイルハンドルの型グロブの話。
私は、この話がまったく理解できておらず、
ラクダ本でこの箇所を調べてみたが、私の脳みそでは理解できず検索してみた。
オライリーのCGIプログラミングを読んでいるのですが、 p309にで… - 人力検索はてな
なるほど。
「ベアワードを許さない」「myはベアワードも許さない」「リファレンスがなかった」
というのが理由なわけか。
とすごく納得できた。