[英]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.