Perl';s主包-块语法-杂注和开始/结束块
我看到了这个问题:并且思考了Perl';s主包-块语法-杂注和开始/结束块,perl,Perl,我看到了这个问题:并且思考了主包。当我写脚本时,比如: ---- 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 l
主包
。当我写脚本时,比如:
---- 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 ----
问题1:以上说法正确吗?主程序包会发生这种情况吗
现在BEGIN/END
块和pragmas。如果我没有弄错的话,在编译阶段会有一些问题需要处理。因此:
---- 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 ----
问题是-这里有什么好处吗
---- 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;
}
---- begin of the file ---
use strict;
use warnings;
package main {
my $var;
}
因此,问题是:
- 在块语法的上下文中,如何准确处理
、杂注
块和开始/结束/检查
主包
- 当将“文件范围”更改为“块范围”时,或者如果没有更改,“标准主包”到“主包{block}”的等效翻译是什么
---- 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
是如何进入主程序包的?
因此这在某种程度上被翻译为:
---- 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
还有两种方法可以声明变量:
使使用变量qw($var)
在包内的任何位置引用当前包中的变量$var
使我们的$var
引用当前块中的$var
语句时在包中的当前变量我们的
use warnings;
use strict;
package main {
# ...
}
你写得很好
package main {
use warnings;
use strict;
package main {
# ...
}
}
既然包装是一样的,那就和
package main {
use warnings;
use strict;
{
# ...
}
}
换句话说,包在文件的开头是
main
,并且隐式块范围(文件范围)是打开的。当您重新输入main
包时,它没有任何效果,如果它与块关联,它的行为与任何块一样。范围和执行顺序彼此几乎没有关系
是,默认包是main
。所以可以说
---- begin file ----
1: #!/usr/bin/perl
2: my $var;
3: ...;
---- end file ----
相当于
---- begin of the file ---
package main { #1st line
my $var; #variable block scope
...
} #last line
---- end of the 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
与pragmas类似:完全解析at后,立即执行use
语句。在下一个语句中,所有导入都可用
像BEGIN
这样的块在正常控制流之外执行,但遵守范围规则
BEGIN块在完全解析后立即执行。返回值将被丢弃
当解释器以正常方式退出时,执行结束块
当我们有
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: main
before package main: main
in package main: main
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
Global symbol "$var" requires explicit package name at - line 8.
BEGIN not safe after errors--compilation aborted at - line 10.
42
undef
undef
这里我们可以看到,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 2: 1
BEGIN 1: 2
BEGIN: main
before package main: main
in package main: main
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
Global symbol "$var" requires explicit package name at - line 8.
BEGIN not safe after errors--compilation aborted at - line 10.
42
undef
undef
因此,在重新声明之前,我们处于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__ }
}
}
输出:
BEGIN 2: 1
BEGIN 1: 2
BEGIN: main
before package main: main
in package main: main
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
Global symbol "$var" requires explicit package name at - line 8.
BEGIN not safe after errors--compilation aborted at - line 10.
42
undef
undef
关于这一点:
问题是-这里有什么好处吗
---- 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;
}
---- 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;
输出:
BEGIN 2: 1
BEGIN 1: 2
BEGIN: main
before package main: main
in package main: main
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
Global symbol "$var" requires explicit package name at - line 8.
BEGIN not safe after errors--compilation aborted at - line 10.
42
undef
undef
变量没有在BEGIN块内声明,因为它是在声明之前编译和执行的(没有完全执行)。因此,strict
发出此错误。由于此错误发生在编译BEGIN
块期间,因此未执行此块
由于作用域,您不能总是以避免使用BEGIN
块的方式对源代码重新排序。以下是你永远不应该做的事情:
for (1 .. 3) {
my $var;
BEGIN { $var = 42 };
say $var // "undef";
}
输出:
BEGIN 2: 1
BEGIN 1: 2
BEGIN: main
before package main: main
in package main: main
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
Global symbol "$var" requires explicit package name at - line 8.
BEGIN not safe after errors--compilation aborted at - line 10.
42
undef
undef
因为每当块离开时,$var
就被清空。(这可能是未定义的行为,并且可能会更改。这至少在v5.16.3和v5.14.2下运行)
编译程序时,不会发生重新排序。相反,BEGIN块在编译后立即执行
有关运行“检查”和“结束”的确切时间,请通读。您是否尝试过所有可能的方法?在变量中添加一些值并打印一些内容,然后查看。请发布可编译的代码;必须修复
使用warnigs代码>到使用警告代码>不会激发信心。你写过几次“what is equired to”,但我认为你的意思是“what is equired to”。使用“what”通常被视为提问。我还没有解决这个问题,因为你可能想问