繁体   English   中英

Perl的主要软件包-块语法-编译指示和BEGIN / END块

[英]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;
  }

所以问题是:

  • BLOCK语法的上下文中,如何精确地处理pragmasBEGIN/END/CHECK块和main package
  • 将“文件范围”更改为“块范围”时-或如果未更改,则“标准主包”到“主包{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如何进入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状态。

strictwarnings语法具有词法范围,因此尽早声明它们是很好的。

# 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM