俺による俺のためのオブジェクト指向講座。その4

今日はさらにがんばって第四回。
PerlOOPをやる上での前提知識シリーズ。

変数のスコープとか

変数や関数はパッケージによって空間が分けられるという話を前回はした。
しかしそれで全てではなく、変数に関してはさらにローカル、レキシカルという区分がある。

いわゆるスコープというやつだが、Perlにはlocal,my,ourという3つの宣言がある。
それぞれの特徴は以下の通り。

local:宣言したブロック内にいる間だけ、指定した変数の値を書き換える
my:宣言されたブロック内でのみ有効な新しい変数を生成する
our:カレントパッケージのグローバル変数を宣言する

この辺りはちょいと分かりづらい。
言ってる自分自身あやふやな感じがしてる。

構文的な使い方は似てるけれど、使途はかなり違う。特にour。

まずは動作のサンプルを。

$a = 1;

sub foo {
  local $a = 2;
  print "local a is $a\n";
}

sub bar {
  my $a = 2;
  print "my a is $a\n";
}

sub buzz {
  our $a = 2;
  print "our a is $a\n";
}

print $a."\n";
foo();
print $a."\n";
bar();
print $a."\n";
buzz();
print $a."\n";

実行結果は

1
local a is 2
1
my a is 2
1
our a is 2
2

こうなる。

ここで言いたいことは、localとmyはグローバルな変数を書き換えず、その場限りの値を作り出すのに対して、ourはグローバル変数そのものを読み書きしているということ。
これで(local,my)と(our)でグループ分けができた。
つまり、同じパッケージ内ならどこからourしても同じ

さらに次のサンプル。

$a = 1;

sub foo {
  local $a = 2;
  print "local";
  buzz();
}

sub bar {
  my $a = 2;
  print "my";
  buzz();
}

sub buzz {
  print " a is $a\n";
}

print $a."\n";
foo();
print $a."\n";
bar();
print $a."\n";
1
local a is 2
1
my a is 1
1

これが表わしているのは、localが宣言した階層以下全てに対して作用し、myは宣言した階層のみに作用するということ。
myの方がより影響範囲が少ないということになる。
基本的にはmyを多用することになると思う。
localが必要な場面といえば、Perlの特殊変数を一時的に変更しておくなどの高度なものになるだろう。

リファレンス

Perlでのポインタのようなもの。
変数のアドレスを格納しているもの。

my $a = 1;
my $ref = \$a;

print $$ref; # 1

リファレンス演算子\(バックスラッシュ)でリファレンスを作成し、リファレンス元の変数型でデリファレンスする。

配列、ハッシュもリファレンス可能。

my @arr = (1..3);
my %hash = (foo => 'bar');

my $ref = \@arr;
my $ref2 = \%hash;

push (@$ref, keys %$ref2);

print $ref->[0]; # 1
print $ref2->{foo}; # bar

デリファレンスにはアロー演算子(->)も使用可能。

リファレンスをデリファレンスしたものを変更すると元の値も変わる。

my $a = 1;
my $ref = \$a;

$$ref = 2;

print $a; # 2

リファレンスはアドレスのサイズ分(と少し)しかメモリを消費しないので、引数にするときはアドレス渡しが便利。

ちなみにポインタのように加算減算はできない。

祝福する

これがPerlOOPの要。
文字通りのbless関数。

my $obj = bless $ref, $pkg;

という構文で、引数に与えたリファレンスをパッケージ名で「祝福」する。
blessされたリファレンス($obj)は$pkgに属し、該当パッケージ内の情報を参照することができる。

これがPerlにおけるインスタンスになる。
詳しくは話を進めながら徐々に。

というわけで

今日はここまで。