[英]Perl's main package - block syntax - pragmas and BEGIN/END blocks
我看到了這個問題: “標准”和塊包裝聲明之間有什么區別嗎? 考慮main package
。 當我編寫腳本時,例如:
---- begin of the file ---
#!/usr/bin/perl #probably removed by shell?
my $var; #defined from now up to the end of file
...
---- end of the file ----
這會自動進入main
包,因此據我所知,接下來會發生。
---- begin of the file ---
{ #<-- 1st line
package main;
my $var; #variable transformed to block scope - "up to the end of block"
...
} # <-- last line
---- end of the file ----
相當於
---- begin of the file ---
package main { #1st line
my $var; #variable block scope
...
} #last line
---- end of the file ----
問題1:以上權利嗎? 主軟件包會發生這種情況嗎?
現在, BEGIN/END
塊和編譯指示。 如果我理解正確,則在編譯階段進行處理。 因此具有:
---- begin of the file ---
#!/usr/bin/perl
use strict; #file scope
use warnings; #file scope
my $var; #defined from now up to the end of file
BEGIN {
say $var; #the $var is not known here - but it is declared
}
...
---- end of the file ----
$var
被聲明,但是這里
---- begin of the file ---
#!/usr/bin/perl
use strict; #file scope
use warnings; #file scope
BEGIN {
say $var; #the $var is not known here - but "requires explicit package name" error
}
my $var; #defined from now up to the end of file
...
---- end of the file ----
沒有聲明$var
。
那么上述內容如何轉換為“默認主程序包”?
它始終是:
---- begin of the file ---
{
package main;
use strict; #block scope ???
use warnings; #block scope ???
my $var; #defined from now up to the end of block
BEGIN { #NESTED???
say $var; #the $var is not known here - but declared
}
...
}
---- end of the file ----
相當於
---- begin of the file ---
package main {
use strict; #block scope
use warnings; #block scope
my $var; #defined from now up to the end of block
BEGIN { #NESTED block
say $var;
}
...
}
---- end of the file ----
問題是-使用類似的東西在_ANY有好處嗎?
---- begin of the file ---
use strict; #always should be at the START OF THE FILE - NOT IN BLOCKS?
use warnings;
#not NESTED
BEGIN {
}
package main {
my $var;
}
所以問題是:
pragmas
, BEGIN/END/CHECK
塊和main package
? 和最后的代碼:
---- begin of the file ---
use strict; #always should be at the START OF THE FILE - NOT IN BLOCKS?
use warnings;
my $var;
#not NESTED
BEGIN {
}
package main {
}
my $var
如何進入main package?
因此,這被翻譯為:
---- begin of the file ---
use strict; #always should be at the START OF THE FILE - NOT IN BLOCKS?
use warnings;
#not NESTED
BEGIN {
}
package main {
my $var; #### GETS HERE????
}
抱歉,文字牆...
當用my
聲明變量時,它不在任何包中 。 完全沒有 塊范圍與任何程序包嚴格不同。 該變量僅在沒有包裝限定的情況下有效,直到最里面的封閉塊的右括號( }
為止。 如果您編寫$main::var
或$::var
,它將是不同的變量。
use warnings;
use strict;
package main {
my $var = 'this';
}
$var; # error, $var was not declared in this scope
say $main::var; # says nothing
還有兩種聲明變量的方法:
use vars qw($var)
使$var
引用當前程序包中位於程序包中任何位置的變量。 our $var
使得$var
引用包中的變量,該變量在當前塊中our
聲明時是當前的。 塊包裝聲明是一個塊,並將其內容放入包裝中。 無塊包聲明將以下內容放入另一個包,但是當前塊作用域仍在繼續。
另一個缺少的地方是
use warnings;
use strict;
package main {
# ...
}
你已經有效地寫了
package main {
use warnings;
use strict;
package main {
# ...
}
}
而且由於包裝相同,因此與
package main {
use warnings;
use strict;
{
# ...
}
}
換句話說,該包在文件的開頭是main
,並且一個隱式塊作用域(文件作用域)已打開。 當您重新輸入main
包時,它沒有任何作用,並且如果它與block相關聯,它的行為就像任何block。
范圍和執行順序彼此無關。
是的,默認軟件包是main
。 所以可以說
---- begin file ----
1: #!/usr/bin/perl
2: my $var;
3: ...;
---- end file ----
相當於
package main {
---- begin file ----
1: #!/usr/bin/perl
2: my $var;
3: ...;
---- end file ----
}
除非指定了其他main
軟件包,否則僅假定main
軟件包。 這不會更改行號等。
遇到變量聲明時,它將立即添加到已知變量列表中。 或更准確地說,一旦聲明所在的語句結束,就:
my # $var unknown
$var # $var unknown
= # $var unknown
foo() # $var unknown
; # NOW $var is declared
對於編譯指示類似:完全解析后立即執行use
語句。 在下一條語句中,所有導入均可用。
像BEGIN
這樣的塊是在常規控制流之外執行的,但要遵循作用域規則。
BEGIN塊在完全解析后立即執行。 返回值將被丟棄。
當解釋器以正常方式退出時,將執行END塊。
當我們有
my $var = 1; # $var is now declared, but the assignment is run-time
BEGIN {
# here $var is declared, but was not assigned yet.
$var = 42; # but we can assign something if we like
}
# This is executed run-time: $var == 1
say $var;
BEGIN {
# This is executed immediately. The runtime assignment has not yet happened.
# The previous asignment in BEGIN did happen.
say $var;
}
結果?
42
1
請注意,如果我在運行時未分配新值,則此變量將保留其編譯時值:
my $var;
...; # rest as before
然后我們得到
42
42
塊可以任意嵌套:
my $var;
if (0) {
BEGIN {
say "BEGIN 1: ", ++$var;
BEGIN {
say "BEGIN 2: ", ++$var;
BEGIN { $var = 0 }
}
}
}
輸出:
BEGIN 2: 1
BEGIN 1: 2
在這里我們可以看到BEGIN塊是在if (0)
被優化之前執行的,因為BEGIN是立即執行的。
我們還可以詢問一個塊位於哪個包中:
BEGIN { say "BEGIN: ", __PACKAGE__ }
say "before package main: ", __PACKAGE__;
# useless redeclaration, we are already in main
package main {
say "in package main: ", __PACKAGE__;
}
輸出:
BEGIN: main
before package main: main
in package main: main
因此,在重新聲明之前,我們已經處於main
地位。 包不是密封的,不變的實體。 它是一個我們可以隨意重新輸入的名稱空間:
package Foo;
say "We are staring in ", __PACKAGE__;
for (1 .. 6) {
package Bar;
say "Loop $_ in ", __PACKAGE__;
if ($_ % 2) {
package Baz;
say "... and in ", __PACKAGE__;
BEGIN { say "just compiled something in ", __PACKAGE__ }
} else {
package Foo;
say "... again in ", __PACKAGE__;
BEGIN { say "just compiled something in ", __PACKAGE__ }
}
}
輸出:
just compiled something in Baz
just compiled something in Foo
We are staring in Foo
Loop 1 in Bar
... and in Baz
Loop 2 in Bar
... again in Foo
Loop 3 in Bar
... and in Baz
Loop 4 in Bar
... again in Foo
Loop 5 in Bar
... and in Baz
Loop 6 in Bar
... again in Foo
因此,關於此:
現在的問題是-在這里使用像任何益處:
---- begin of the file --- use strict; use warnings; package main { my $var; }
答案是否定的 :如果我們已經在包main
,則重新聲明它沒有好處:
say __PACKAGE__;
package main {
my $var;
say __PACKAGE__;
}
say __PACKAGE__;
如果執行,我們就能看到我們始終處於main
狀態。
strict
和warnings
語法具有詞法范圍,因此盡早聲明它們是很好的。
# no strict yet
use strict;
# strict now activated
BEGIN {
# we are still in scope of strict
$var = 1; # ooh, an undeclared variable. Will it blow up?
say "BEGIN was executed";
}
my $var;
輸出:
Global symbol "$var" requires explicit package name at - line 8.
BEGIN not safe after errors--compilation aborted at - line 10.
該變量未在BEGIN塊內聲明,因為它已在聲明之前進行編譯(且執行不充分)。 因此, strict
發出此錯誤。 由於在BEGIN
塊的編譯期間發生了此錯誤,因此未執行該塊。
由於作用域,您不能總是以避免使用BEGIN
塊的方式對源代碼進行重新排序。 這是您永遠不應該做的事情:
for (1 .. 3) {
my $var;
BEGIN { $var = 42 };
say $var // "undef";
}
輸出:
42
undef
undef
因為只要離開該塊,就會清空$var
。 (這可能是不確定的行為,並且可能會更改。至少在v5.16.3和v5.14.2下運行)。
編譯程序時,不會進行任何重新排序。 相反,BEGIN塊在編譯后立即執行。
有關運行CHECK和END的確切時間,請閱讀perlmod 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.