凄く今更。
こっちの記事を書いたついでに。our
での検索上位を占めているページに思う所があったので書いとく。1
「〜な変数の宣言」と書かれた場合の一般的な受け取り方としては、「これこれこう言う機能を持った変数です、との宣言」として受けとるだろう。本稿もその前提で記載する。
主張
our
の機能は、巷で良くタイトルにされる「パッケージ変数の宣言」ではない。2
our
の機能は、該当レキシカルスコープ内で、「パッケージ変数へのエイリアスを宣言する」だけのものである。
つまり、our $h
とすれば、そのパッケージのパッケージ変数(通常はmain
なので $main::h
)へのエイリアスを宣言し、パッケージ名 (main::
) を省略可能にする。
それ以上でも以下でもない。
パッケージ変数の宣言
では、パッケージ変数の宣言は、どうするのか?
パッケージ変数($Foo::bar
) は最初に使われたときにひょっこり現われる3 もので、完全に修飾された変数 4 である為、use strict
のエラー対象外となるもの。そのため宣言は必要ない。
強いて言えばパッケージ名自体が宣言の様なものだ。
our $h
がパッケージ変数の宣言と言われるのは、
- たまたま、
$main::h
を先に弄ってなくて、 -
our $h
を実行したと同時に$main::h
がひょっこり現われた
だけ。
パッケージ変数に宣言は必要ない。(2回目)
no warnings; no strict; 時
改めて書くのもアレだが、no warnings; no strict;
での(宣言無しの)新たな変数は全て、パッケージ変数($Foo::bar
)だ。もっと言えば、our
を省略した 5 パッケージ変数のエイリアス。
# no warnings, no strict の場合
% perl -le '$s = 10; print $main::s;' -M-warnings -M-strict
10
ついでに、 local について
パッケージ変数($Foo::bar
)関係なので、local
も取り上げる。
"local" はリストアップされた変数を、囲っているブロック、 ファイル、eval の中で、ローカルなものにします。6
で、変数関連と特長は、
- 事実上、パッケージ変数専用
- ダイナミックスコープ7を取る
である。
変数の相関関係で言うと
.
+-- パッケージ変数($Foo::bar) # our でエイリアス作成可能
| +-- local 変数
+-- my 変数
+-- state 変数
の様な形。
で、パッケージ変数専用と意識すると、local
が ダイナミックスコープであるのは自明となる。
例文で書かれがちな ↓ の様な記載は、
#!/usr/bin/env perl
no strict;
no warnings;
sub test () { print $var . "\n";}
$var = 100;
test();
{
local $var = 10;
test();
}
# output
# 100
# 10
パッケージ名を明記するだけで、レキシカルスコープであると考える事自体が、パッケージ変数の存在意義を否定してしまう事が分る。
#!/usr/bin/env perl
use strict;
use warnings;
sub test () {
# レキシカルスコープとしたら、ここで以下の様に直接書く事は出来ず
# @_ 経由の引渡しが必要となってくる。
# そうすると、パッケージ変数自体のメリットは皆無となってしまう。
print $main::var . "\n";
}
$main::var = 100;
test();
{
local $main::var = 10;
test();
}
# output
# 100
# 10
再び、 our について
さて、our
に戻り、多少の挙動例を記載して本稿を締める。
レキシカルスコープを跨いで複数回宣言するのはダメ。
% perl -le 'package test; $test::s = 10; our $s; { our $s; print $s; } print $s;' -Mstrict -Mwarnings
"our" variable $s redeclared at -e line 1.
(Did you mean "local" instead of "our"?)
10
10
前の our
のスコープが消滅してれば、our
しても良い。
# OK: 跨いでないから
% perl -le 'package test; $test::s = 10; { our $s; print $s; } our $s; print $s;' -Mstrict -Mwarnings
10
10
local
した後に our
しても、our
した後に local
しても OK8
% perl -le 'package test; $test::s = 10; { local $test::s = 100; our $s; print $s; } print $test::s; 1;' -Mstrict -Mwarnings
100
10
% perl -le 'package test; $test::s = 10; { our $s; local $s = 100; print $s; } print $test::s; 1;' -Mstrict -Mwarnings
100
10