我看到了这个问题:Is there any difference between "standard" and block package declaration?并在考虑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????
}
对不起文字之墙......
答案 0 :(得分:4)
当您使用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
包时,它没有任何效果,如果它与块关联,它的行为与任何块一样。
答案 1 :(得分:1)
范围和执行顺序彼此无关。
是的,默认包是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
包,除非指定了另一个包。这不会改变行号等。
遇到变量声明时,会立即将其添加到已知变量列表中。或者更准确地说,只要声明它的声明已经结束:
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
在这里,我们可以看到在优化if (0)
之前执行BEGIN块,因为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
关于这一点:
问题是 - 在这里 ANY 使用类似的东西
---- 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。