2

私はこの質問を見ていて、遊んでいるときにこれに出くわしました:

#! /usr/bin/env perl
#
# use warnings;
use strict;
use feature qw(say);

{
    our $foo = "bar";
    say "Foo = $foo";
}

say "Foo = $foo";  # This is line #12

はい、use warnings;電源を切りました...

これを実行すると、次のようになります。

Variable "$foo" is not imported at ./test.pl line 12.
Global symbol "$foo" requires explicit package name at ./test.pl line 12.
Execution of ./test.pl aborted due to compilation errors.

うーん...同じ「変数 "$foo" は ./test.pl 行 12 にインポートされていません。 」というエラーが表示されmy $foo = "bar";ます。ブロックを離れるとmy変数がないため、使用するとこれを理解できます。$fooただし、our変数はパッケージスコープであると想定されています。$fooその時点で価値がないかもしれないことは理解できましたが、これは?

また、「Variable "$foo" is not import at ./test.pl line 12.」はどういう意味ですか? パッケージとインポートについては理解していますが、ここにはパッケージが 1 つしかありませんmain。パッケージ$fooに入っている必要があります。mainインポートする必要はありません。

スコープ外になった後、パッケージに含まれていないように見えるパッケージ変数で何が起こっていますか?


補遺

したがって、 を使用$::fooしたり、 で別のエイリアスを作成したりしour $foo;た場合、プログラムは期待どおりに動作します。cmj

これを試してみましょう...

#! /usr/bin/env perl
#
# use warnings;
use strict;
use feature qw(say);

{
    our $foo = "bar";
    say "Foo = $foo";
}

our $foo;          # Redeclared
say "Foo = $foo";  # This is line #12

これで、次のように出力されます。

bar
bar

回答したすべての人が指摘したように、同じ名前のパッケージ変数にエイリアスourを作成するだけで、レキシカルスコープです。つまり、エイリアスが範囲外になると、withの値にアクセスできなくなります。それは私が今まで気づかなかったことです。$main::foo$foo

ただし、 cjm が指摘したように、再宣言our $foo;するとエイリアスが復元され、既存の$main::fooは新しい にエイリアスされます$foo。再宣言するour $foo;と、 の値$foo復元されます。

ourこれは、非常に紛らわしい変数の 1 つです。宣言が表示our $foo;され、突然その変数が存在するだけでなく、不思議な値が含まれています。プログラムを検索して、その値がどこから来たのかを確認する必要があります。

4

3 に答える 3

5

パッケージ変数への字句エイリアスを宣言しますこれは、 のようにスコープが設定されていることを意味しmyます。違いは、パッケージ変数によってサポートされているため、スコープを終了しても変数が消えないことです。エイリアスだけが消えます。

したがって、 を使用$::fooしたり、 で別のエイリアスを作成したりしour $fooた場合、プログラムは期待どおりに動作します。

于 2014-03-05T15:18:33.530 に答える
2

「変数 "$foo" は ./test.pl 行 12 でインポートされません。」平均?

perldiag 言います:

「厳密な使用」が有効な場合、別のモジュールからインポートされたと思われるグローバル変数を参照しました。これは、同じ名前の何か (通常はサブルーチン) がそのモジュールによってエクスポートされているためです。これは通常、変数の前に間違った変な文字を入れたことを意味します。

何もインポートしていないので意味がありません。コードによって発行されるべきではありません。Perl は厳密なエラーの診断に役立てようとしていますが、間違っていました。警告を無視します。


ただし、変数はパッケージスコープであると想定されています

それは真実ではない。ourのようにレキシカル変数を作成しますmy。その変数は、同じ名前のパッケージ変数にエイリアスされます。

package Foo;
our $x;         # Equivalent to: alias my $x = $Foo::x;
$Foo::x = 123;
package Bar;
$Bar::x = 456;
print("$x\n");  # 123

( aliasData::Alias によって提供されます。)

于 2014-03-05T15:17:20.443 に答える
2

パッケージの範囲を示すものではありません。

our 宣言は、レキシカル スコープ全体、さらにはパッケージの境界を越えて見えるパッケージ変数のエイリアスを宣言します。

これは、それを宣言したブロックのレキシカルスコープが終了すると、スコープ外になることを意味します。

于 2014-03-05T15:10:45.113 に答える