型グロブとは?
Perlでは、各パッケージの名前空間と、名前を有する要素の各データ型の名前空間がパッケージ内で個別に保持されています。
したがって、ある特定のパッケージ内で、変数$FILE,@FILE,%FILE,&FILEを持つことができるわけです。
で、このパッケージ全体にアクセスするために、型グロブというものを使用します。この、パッケージってところが注意ですね。my宣言された変数はパッケージとは関係なくなってしまいますからね!
「FILE」という名前を有する$FILEや@FILE全てを参照したい場合は
*FILE
と記述すればいいみたいです。
この*FILEには各データ、$FILEや@FILEなどへのリファレンスが入っています。
*FILE = *HOGE
と、記述すると、右側の型グロブに入っているリファレンスが左側の型グロブの一致するものに割り当てられます。
また、次のように書くと対応する種類の型グロブのみ置換することもできます。
*FILE = \$HOGE
では、プログラムを書いてみましょう!!
$hoge = "hoge"; $muge = "muge"; @hoge = (1,2,3,4,5); @muge = (6,7,8,9,10); #スカラーの部分だけを型グロブを使って割り当てる *muge = \$hoge; print $muge; # hoge と表示 print @muge; # 678910 と表示
$mugeの値が、hogeに変わりましたね!!
この型グロブは、これからいろいろなところで役に立ってきそうですね!!
と、この型グロブもそうですがホントに簡単に勉強してきましたが次回は継承について少しずつ勉強していこうと思います。今まで早足で勉強してきた感じもするので、これから勉強をしていてまた分からないことがでてきたらまとめていこうと思います。
あと、今日の型グロブについてはもう少しまとめないといけなさそうなので、次回までの課題ということで・・・。
■
今回はクロージャについて勉強しようと思います。
まずは、ソースから。
{ my $data = 10; sub hoge { my ($val) = @_; $data = $data + $val; return $data; } } my $test = hoge(100); print $test; #110
上記の例で話をすると、$dataのスコープは$dataを宣言した位置から、それを囲むブロックの末尾までですよね。
しかし、サブルーチン「hoge」を定義することによって、それ以外の場合では破棄される$dataの値が維持されるみたいなんですよ。
したがって、$dataの有効なスコープを過ぎたあとに、$dataにアクセスするにはサブルーチン「hoge」を呼び出せばいいみたいです。
ということは、「クロージャとは自身が使用するレキシカル変数を保持するサブルーチンである」って感じの覚え方でいいのかな?
もちろんリファレンスで受け取ったりもできます。
#サブルーチン「hoge」のリファレンスを受け取る。 { my $data = 10; sub hoge { my ($val) = @_; $data = $data + $val; return $data; } } my $hoge_ref = \&hoge; print $hoge_ref->(100);#110
同じように、無名サブルーチンでも大丈夫です。
#無名サブルーチンを絡めたクロージャ { sub hoge { my $data = 10; my $sub_ref = sub { my ($val) = @_; $data = $data + $val; return $data; }; return $sub_ref; } } my $sub_ref = hoge();#無名サブルーチンのリファレンス print $sub_ref->(100)."\n";#110
で、ここで重要なのが、複数回、$sub_ref->(100)を実行した時の動作です。
一回目は・・・$sub_ref->(100) #110が返ってくる
二回目は・・・$sub_ref->(100) #210が返ってくる
そうなんです!一回目の呼び出しで、$dataの値が110になっているので、二回目の呼び出しでは「110 + 100」を、行っているんですね!!
とまぁ、こんな感じで簡単ですがクロージャに対して勉強してみました。
まだまだ、勉強していかないといけないことがたくさんあるので、がんばっていこうと思います。
リファレンスとは?
だいぶと期間があいたので、今回はリファレンスについて勉強したいと思います。
まずは、
・リファレンス
リファレンスを一言で言うと実体へのアドレスになる。そのアドレス自体のコトをリファレンスと呼びます。
・デリファレンス
リファレンスが指す先にアクセスする事をデリファレンスと呼ぶ。 perlではポインタ演算が出来ないため、全てのリファレンスはデリファレンスしないと使う事が出来ない。変数へのリファレンスをデリファレンスした状態の場合、通常の変数と同様に扱う事が出来ます。
・スカラーへの代入
$hoge = "hoge"; $data = \$hoge; print $$data; #hogeと表示される
・配列への代入
@list = (100, 200); $scalar = \@list; ${$scalar}[0]; #100が表示される $$scalar[0]; $scalar->[0];
・上記の$scalarには、@listが持つリスト値(正しくは配列)へのリファレンスが代入される。$scalarをデリファレンスする事により、通常のリスト変数と全く同じように使えるが、リファレンス自体はたった一つのスカラー値なのでスカラー変数に代入できる。
・上記の例では@listへのリファレンスになっているが、もし初めから「@list」と言う変数を使う気がないのならば初めから作らなくても構わない。
その場合は、名前のない(変数名を持たない)実体とその実体へのリファレンスを生成する事が出来る。
[ブラケット]は、内部にリストデータ(正しくは配列)を生成し、その実体へのリファレンスを返す。
$scalar = [100, 200]; $$scalar[1] #200が表示される
・ハッシュへの代入
%hash = ( 'data1' => 100, 'data2' => 200 ); $scalar = \%hash; $$scalar{'data1'}; #100が表示される ${$scalar}{'data1'}; $scalar->{'data1'}; $hash{'key'} = \$scalar; ${$hash{'key'}}->{'data1'};
・上記の$scalarには、%hashが持つハッシュへのリファレンスが代入される。 $scalarをデリファレンスする事により、通常のハッシュ変数と全く同じように使える。
ハッシュでも、無名のハッシュデータを生成するコトが出来る。 {ブレス}は、内部にハッシュデータを生成し、その実体へのリファレンスを返す。
$scalar = { 'data1' => 100, 'data2' => 200 };
・矢印演算子(->)
矢印演算子(->)は(->)の左側をデリファレンスする。
・優先順位
まず、「$$scalar[0]」のように書いた場合、先頭の「$」は、添え字の[0]よりも強い。つまり「$scalar[0]」と見なされるよりも早く「$$scalar」と見なされる。よって、「$scalar」がデリファレンスされる。
次にデリファレンスされた「$scalar」の後に添え字があるため、 $scalarはリストへのリファレンスであり、なおかつスカラー値 [0] にアクセスされていることになる。 {ブロック}を使うと「$」や「@」などの解釈よりも先に行われる。
$scalar = [ [ [ [ [100, 200], [101, 201], ], [ [102, 202], [103, 203], ], ], ], ]; ${ ${ ${ ${ ${ $scalar }[0] }[0] }[1] }[1] }[0]; #103が表示される $scalar->[0]->[0]->[1]->[1]->[0];#103が表示される $scalar->[0][0][1][1][0];#103が表示される
と、まぁリファレンスについて勉強しましたが、感想としてはこのリファレンスを使うことによって、いろいろなデータ構造を扱うことができそうですね!!
について
今日は、use strict について勉強したいと思います。
use strictってのは、簡単に言うとプログラムのミスを防ぐ、見つけてくれる!って感じですかね?
use strictには3つの機能?があります。どのような機能かというと
- use strict "vars"; #変数はあらかじめ宣言しなくてはならない
- use strict "refs"; #シンボリックリファレンスは使えない
- use strict "subs"; #裸のワードによる文字列はクォートしなければならない
以上の3つです。
多くのプログラミング言語では、コンパイラにヒントを与えることができます。Perlでは、このようなヒントは、use宣言を用いてコンパイラに伝えられます。これを、プラグマ(pragma)というらしいです。
なるほど、strictもプラグマの1つなんですね!
一部のプラグマはグローバル変数やカレントパッケージに影響を与えるグローバル宣言であるんですが、ほとんどのプラグマは、その効力が、取り囲むブロック、ファイルの末尾までに限定されているようなレキシカルスコープ宣言で、レキシカルスコープを持つプラグマの場合、内側のスコープでno宣言によって効力を打ち消すことができるらしいです。
なるほど、no宣言はちょうどuseの逆の動きをするものなんですね。
それでは話は戻って、use strictの機能を見ていってみましょう!
- strict 'refs'
このrefsはシンボリックリファレンスを使うと、それが意図的であってもそうでなくても実行時エラーを発生させる。
use strict 'refs'; $ref = \$foo; #リファレンスを格納する print $$ref; #デリファレンスしてもOK $ref = "foo"; #グローバル(パッケージ)変数の名前を格納する print $$ref; #strict refsのもとでは実行時エラーになる
シンボリックリファレンスとは以下のようなものです。
$scalar = 'hoge'; $$scalar; #これは「$hoge」と言う変数名を表す。
以上のように記述するだけで、perlはこれをシンボリックリファレンスと認識してしまいます。これは、間違ってしてしまいそうですね・・・。
- strict 'vars'
次に示す基準に該当しない変数にアクセスすると、コンパイル時にエラーが発生する
・Perlによってあらかじめ定義されている変数(@ARGV、%ENVなど)および記号の名前を持つすべてのグローバル変数($_など)
・ourで宣言されたもの(グローバル変数)、またはmyで宣言されたもの(レキシカル変数)
・他のパッケージからインポートされたもの
・パッケージ名およびパッケージセパレータ::によって完全修飾されたもの
プログラム全体で有効なグローバル変数(@ARGVなどのように強制的にパッケージmainに登録されているもの)はエラーの対象にはならない。
この、strict 'vars'が適応されているときは、local宣言はエラーになる。localはただ実行時にそのブロックの範囲で有効な新しい一時的な値を与えるだけで、指定された変数がグローバルであるかどうか、という状態は変更しないからです。グローバル変数を宣言するにはourを使う必要があります。しかし、ourをlocal化することは可能。
local our $hoge;
- strict 'subs'
このsubsは、裸のワードをすべて構文エラーとみなすようになる。文字列を表したい時はクォートで囲む。関数を呼び出したい時は、あらかじめ宣言しておくか、後ろに()をつけるようすると大丈夫みたいです。
use strict 'subs'; $hoge = hoge; #エラー!! 裸のワード $hoge = 'hoge'; #OK $hoge = hoge(); #OK sub hoge; #関数を前もって宣言しておく $hoge = hoge; #これならOK %hash = (hoge => 1,ups => 2,); #「=>」の左側が自動的にクォートされるためOK $hoge = $hoge{ups}; #ブレースによるクォート @array = @hash{"AAA","BBB"}; #OK @array = @hash{qx/AAA BBB/} #OK
とまぁ、use strictの3つの機能をひと通り見ましたけど、こりゃ僕なんかはuse strictを使わないでプログラムを書いてしまうと・・・・。恐ろしいですね。
それでは、今日はこのへんで!
について
だいぶと、Perlの勉強を怠っていたので、そろそろ第2回目の勉強をしようと思います・・・。
今回は「パッケージ」について調べたことを書こうと思います。
まず、パッケージとは何かというと、
「変数とサブルーチンに独立した名前空間を設定するPerlの構成要素」
・・・、なんか想像しずらいですね。
パッケージ宣言をするには、package XXX;と書けば良いみたいです。
有効範囲としてはpackage宣言を囲むスコープを抜けるまでか、他のpackage宣言がされるまで有効です。
とりあえず、プログラムを書いてみよう!
sub call { } package hoge; sub call { } package moge; sub call { }
この例では、callという名前を有する完全に別個の3つのサブルーチンが宣言される。最初のcallは主名前空間(main)で定義され、2つ目のcallは名前空間(hoge)そして、最後のcallは名前空間(moge)内で定義されるみたいです。
なるほど、パッケージ宣言をすることで変数名やサブルーチン名の重複を防ぐことができそうですね。
じゃあこの場合、今いるパッケージから他のパッケージに属しているサブルーチンを使いたいときは、どう記述すればいいんでしょうか?
答えは、ブルーチン名の前にパッケージ名を付け、その2つを二重コロン(::)で区切って記述すると良いみたいです。
package main; hoge::call(); #パッケージ名 hoge内のcall() moge::call(); #パッケージ名 moge内のcall() main::call(); #パッケージ名 main内のcall() call(); #現在のパッケージ内のcall() すなわち、main::call()と同じ
変数に対しても同じことが言えるんですが、この前に勉強した「my宣言」で宣言した変数は、このパッケージに属さないみたいです。これは重要ですね!
じゃあ、「local宣言」は?
前に、localは、グローバル変数に一時的な値を持たせる。と、書きましたが、これは、パッケージ変数に一時的な値を持たせるっていうことになるんだと思います。
あと、myやlocalの他に「our」という宣言の仕方があるようです。
いろいろ調べたんですが、言えること(自分の認識)は、our宣言した名前空間に属するグローバル変数をそのパッケージのパッケージ変数として宣言するって感じでしょうか・・・。間違ってたらすいません。
それと、パッケージのことを調べていて、Perlがどうやって名前を探索するのかも分かりました。
方法としては、まず、その場所を取り囲んでいる最も内側のブロックを先頭に向かってその変数が同じブロック内でmy(またはour)宣言によって宣言されているかを調べる。もしあれば変数はレキシカルスコープを持つ。それでも見つからない場合はそのブロックを取り囲む1つ外側のブロックからレキシカルスコープを持つ変数を探そうとする。宣言がない場合は、取り囲むブロックがなくなるまでこの処理を繰り返す。取り囲むブロックがなくなったら、コンパイル単位全体を1個のブロックとみなして、そこから宣言を探そうとする。コンパイル単位がファイルであれば、これがありうる最大のレキシカルスコープなので、Perlはレキシカルスコープ変数の探索を打ち切って(この状態は、myもourも見つからなかったということ)変数はパッケージ変数であると仮定する。今度は変数宣言の変わりにパッケージ宣言を行う(上記の手順で)もし、パッケージ宣言が見つかれば、パッケージ名が変数の先頭に付けられる。取り囲むどのレキシカルスコープにもパッケージ宣言がない場合は、Perlは実際は名前がないと不便なのでmainという名前でアクセスできるようになっている。だから、パッケージ宣言が見つからない場合は$main::hogeといえるらしいです。
てか、全然知らなかった・・・。
とまぁ、パッケージとは少し反れましたがこの辺で今日はおしまい。
myとlocal
記念すべきPerlの勉強、第1弾として「myとlocalの違い」について勉強したいと思います。
まずは、調べてみて重要だと思った単語
- レキシカル変数
- スコープ
- スコープの有効範囲
- レキシカルスコープ
- ダイナミックスコープ
「my宣言」
myで宣言された変数をレキシカルスコープ変数という。
宣言の仕方は
my $hoge; #宣言のみ my $hoge = 'hello'; #宣言と同時に値も格納 my ($hoge, $moge); #複数の変数名を同時に宣言
などです。
では、レキシカル変数の有効範囲って?
レキシカル変数の有効範囲は、宣言を行った場所からそれを取り込んでいる最も内側のスコープ(ブロック、ファイル)の末尾までが有効範囲となるらしいです。
では、プログラムを書いて確認してみます。
my $val = "apple\n"; { my $val2 = "orange\n"; print $val; #apple print $val2; #orange } print $val; #apple print $val2; #エラー
ちゃんと有効範囲が適応されてますね!
「local宣言」
local を使って定義された変数は、ダイナミックスコープ変数 と呼ぶ。
そして、local を使って変数を宣言することをダイナミックスコープ宣言と呼ぶ。
宣言の仕方は
local $var; #宣言のみ local $var = 'hello'; #宣言と同時に値も格納 local($foo, $var); #複数の変数名を同時に宣言
などです。
では、ダイナミックスコープ変数の有効範囲は?
ブロックが実行されている間、グローバル変数は一時的な値を持つ。
しかし、プログラムがそのダイナミックスコープの末尾に到達すると、一時的な値は捨てられて、元の値に戻される。
「一時的な値は捨てられて」ということはどうゆうことなんでしょうか?
プログラムを書いて確認して見ます。
$val = "apple\n"; { local $val = "orange\n"; print $val; #orange } print $val; #apple
なるほど!ブロックの中だけ一時的に値が変わっていますね!
結論としては、
myは、完全にプライベートな変数を作る。
localは、グローバル変数に一時的な値を持たせる。
と、いったところでしょうか・・・。
まだまだ調べることはたくさんあるようですが今日はここまで・・・。