考慮這個腳本(從我擁有的更大的腳本中總結出來):
#!/usr/bin/perl
use strict;
use warnings;
package help {
my %HELPTEXT;
$HELPTEXT{ "topic" } = "Some help\n";
sub get_help( $ ) {
print $HELPTEXT{ $_[0] };
}
}
package main {
sub main() {
help::get_help( "topic" );
}
}
main();
這有效,列印Some help.
現在,我想將初始化($HELPTEXT{ "topic" } = "Some help\n";和其他類似的)放在腳本的末尾——同時保留package help它的代碼。
但是,這不起作用:
# ...
main();
package help {
$HELPTEXT{ "topic" } = "Some help";
}
錯誤資訊: Global symbol "%HELPTEXT" requires explicit package name (did you forget to declare "my %HELPTEXT"?)
這也不起作用:
main();
$help::HELPTEXT{ "topic" } = "Some help\n";
錯誤資訊:Name "help::HELPTEXT" only used once/ Use of uninitialized value in print。
顯然,我對 Perl 包及其命名空間缺乏了解。
我可以在中間檔案包命名空間中有一個變數,并且仍然在檔案末尾初始化它嗎?
補充:我發現可以通過our以下方式解決宣告問題:
# ...
main();
package help {
our %HELPTEXT;
$HELPTEXT{ "topic" } = "Some help\n";
}
來自 perldoc:
"our" 為當前包中同名的包(即全域)變數創建詞法別名,以在當前詞法范圍內使用。
However, this still gives an error: Use of uninitialized value in print. Even if I wrap the initialization in an INIT {} block.
I'd like to not only have a solution for this, but understand why this isn't working as I expected. Coding by guessing feels bad...
uj5u.com熱心網友回復:
這里有一些事情需要理解,我在Learning Perl 中寫了更多關于這方面的內容。這主要是意識到詞法變數和包變數是兩個不同的系統。任何詞法都不關心默認包是什么。
這是您strict失敗的示例:
use v5.12;
use strict;
package help {
$HELPTEXT{ "topic" } = "Some help";
}
將use strict適用于您使用它(檔案或塊)的任何范圍。在該范圍內,您必須在首次使用時宣告變數或使用完整的包規范。由于你沒有做這些,你會得到錯誤。更改包不會將其關閉。
該package宣告僅更改默認包名稱。使用塊形式,它只更改該塊中的默認包。任何詞法都無關緊要,包括詞法變數。這$foo并不關心默認包是什么,因為它不是包變數。無論默認包是什么,它都會持續到作用域(塊或檔案)結束:
use v5.12;
use strict;
use warnings;
package help;
my $foo = 'bar';
package main;
say $foo; # outputs bar
our當您在同一范圍內組合包時,使用替代會產生奇怪的效果。您將獲得一個具有該名稱的詞法變數,該變數在范圍內的任何地方都可用,并且您將獲得一個具有該名稱的包變數(在程式中的任何地方都可用)。它們使用相同的資料,因此更改任何一個都會更改資料,并且兩個版本都表明:
use v5.12;
use strict;
use warnings;
package help;
our $foo = 'bar';
package main;
say $foo; # bar
say $help::foo; # bar
$help::foo = 'baz';
say $foo; # baz
say $help::foo; # baz
這在package BLOCK表單中不起作用,因為將our詞法別名限制為該塊,即使包版本仍然存在(并且不限于塊):
use v5.12;
use strict;
use warnings;
package help {
our $foo = 'bar';
}
say $help::foo; # bar
您可以指定完整的包規范,在這種情況下strict不再關心:
use v5.12;
use strict;
package help {
$help::HELPTEXT{ "topic" } = "Some help";
}
或者,use vars:
use v5.12;
use strict;
package help {
use vars qw(%HELPTEXT);
$HELPTEXT{ "topic" } = "Some help";
}
你想要一些help包裝的東西在頂部,然后一些更多的help包裝東西在底部。由于package剛剛更改了默認包,您可以再次使用它。也就是說,您不僅限于使用一次,也不必將所有內容都放在第一個help塊中:
use v5.12;
use strict;
use warnings;
package help {
use vars qw(%HELPTEXT);
sub help { $HELPTEXT{$_[0]} }
}
say "TOPIC: " . help::help("topic");
package help {
use vars qw(%HELPTEXT);
$HELPTEXT{ "topic" } = "Some help";
}
This doesn't work because these are all run time statements. Perl compiles all of this, but it's then going to execute the statements in order. That means that the $HELPTEXT{ "topic" } = "Some help"; doesn't run until the very end, after you try to use it.
A BEGIN solves that:
#!/usr/bin/perl
use v5.12;
use strict;
use warnings;
package help {
use vars qw(%HELPTEXT);
sub help { $HELPTEXT{$_[0]} }
}
say "TOPIC: " . help::help("topic");
BEGIN {
package help {
use vars qw(%HELPTEXT);
$HELPTEXT{ "topic" } = "Some help";
}
}
When Perl compiles this, it reaches the BEGIN block and compiles it, but then runs its block immediately. The package variable for %HELPTEXT is setup and available anywhere in the program. By the time the top package help {} is run, that hash is already set up. It might be easier to see with some messages thrown in:
use v5.12;
use strict;
use warnings;
package help {
use vars qw(%HELPTEXT);
say "Setting up rest of help";
sub help { $HELPTEXT{$_[0]} }
}
say "TOPIC: " . help::help("topic");
BEGIN {
package help {
use vars qw(%HELPTEXT);
say "Setting up messages";
$HELPTEXT{ "topic" } = "Some help";
}
}
The output shows the order. The BEGIN runs first, then the top pf the script, and then the middle:
Setting up messages
Setting up rest of help
TOPIC: Some help
但是,如果你有一個詞法變數,就會發生一些不同的事情。包變數在那里,但詞法版本在它在范圍內時掩蓋了它:
use v5.12;
use strict;
use warnings;
$help::foo = 'quux';
say "Before: $help::foo";
package help {
my $foo = 'bar';
say "Inside: $foo";
}
say "After: $help::foo";
輸出顯示:
之前:quux 內部:bar 之后:quux
但是,請記住詞匯屏蔽僅在塊內。如果你呼喚不在那個范圍內的東西,
use v5.12;
use strict;
use warnings;
$help::foo = 'quux';
say "Before: $help::foo";
package help {
my $foo = 'bar';
say "Inside: $foo";
main::show_foo();
}
say "After: $help::foo";
sub show_foo { say "show_foo: $help::foo" }
輸出顯示,即使在塊內呼叫時,也會show_foo使用包版本,盡管該子例程位于不同的包中:
Before: quux
Inside: bar
show_foo: quux
After: quux
因此,訣竅是知道您的變數是詞法的(受范圍影響)還是包。
uj5u.com熱心網友回復:
INIT確實有效(雖然BEGIN更常見)。
#!/usr/bin/perl
use strict;
use warnings;
package help {
our %HELPTEXT;
$HELPTEXT{ "topic" } = "Some help\n";
sub get_help( $ ) {
print $HELPTEXT{ $_[0] };
}
}
package main {
sub main() {
help::get_help( "topic" );
}
}
main::main();
INIT {
package help;
our %HELPTEXT;
$HELPTEXT{ "topic" } = "Some help\n";
}
$ perl a.pl
Some help
我想你還在my %HELPTEXT;第一個街區?
而不是使用our兩次,你可以使用
use vars qw( %HELPTEXT );
無論如何,你正在做的是一團糟。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/349240.html
標籤:perl package initialization
上一篇:IPCmsgsnd意外等待
