简体   繁体   English

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

[英]Perl's main package - block syntax - pragmas and BEGIN/END blocks

I saw this question: Is there any difference between "standard" and block package declaration? 我看到了这个问题: “标准”和块包装声明之间有什么区别吗? and thinking about the main package . 考虑main package When I write a script, like: 当我编写脚本时,例如:

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

this automatically comes into the main package, so as I understand right the next happens. 这会自动进入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 ----

which is equivalent to 相当于

---- begin of the file ---
package main { #1st line
  my $var; #variable block scope
  ...
} #last line
---- end of the file ----

Question 1: Is the above right? 问题1:以上权利吗? That happens with the main package? 主软件包会发生这种情况吗?

Now the BEGIN/END blocks and pragmas. 现在, BEGIN/END块和编译指示。 There are handled in the compilation phase, if I understand right. 如果我理解正确,则在编译阶段进行处理。 So having: 因此具有:

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

the $var is declared, but here $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 ----

the $var is not declared. 没有声明$var

So how is the above translated to "default main package"? 那么上述内容如何转换为“默认主程序包”?

It is always: 它始终是:

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

which is equivalent of 相当于

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

The question is - is here _ANY benefit using something like: 问题是-使用类似的东西在_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;
  }

So the question is: 所以问题是:

  • how exactly are handled the pragmas , BEGIN/END/CHECK blocks and the main package in a context of BLOCK syntax ? BLOCK语法的上下文中,如何精确地处理pragmasBEGIN/END/CHECK块和main package
  • when changes the "file scope" to the "block scope" - or if it not changes, what is the equivalent translation of "standard main package" to "main package {block}" 将“文件范围”更改为“块范围”时-或如果未更改,则“标准主包”到“主包{block}”的等效翻译是什么

and the last code: 和最后的代码:

  ---- 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 {

  }

How does the my $var get into the main package? my $var如何进入main package? So this is translated to somewhat as: 因此,这被翻译为:

  ---- 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????
  }

Sorry for the wall of text... 抱歉,文字墙...

When you declare the variable with my , it is not in any package . 当用my声明变量时,它不在任何包中 At all. 完全没有 The block scope is strictly distinct from any package. 块范围与任何程序包严格不同。 The variable is valid until the closing brace ( } ) of the innermost enclosing block only without package qualification. 该变量仅在没有包装限定的情况下有效,直到最里面的封闭块的右括号( }为止。 If you wrote $main::var or $::var , it would be different variable. 如果您编写$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

There are two more ways to declare variables: 还有两种声明变量的方法:

  • use vars qw($var) makes $var refer to the variable in current package wherever inside the package. use vars qw($var)使$var引用当前程序包中位于程序包中任何位置的变量。
  • our $var makes $var refer to the variable in package that was current at the time of the our statement within current block. our $var使得$var引用包中的变量,该变量在当前块中our声明时是当前的。

The block package declaration is a block and puts it's content in a package. 块包装声明是一个块,并将其内容放入包装中。 Whereas the block-less package declaration puts following content in another package, but the current block scope continues. 无块包声明将以下内容放入另一个包,但是当前块作用域仍在继续。

The other missing bit is that when you write 另一个缺少的地方是

 use warnings;
 use strict;
 package main {
 # ...
 }

you've effectively written 你已经有效地写了

 package main {
     use warnings;
     use strict;
     package main {
     # ...
     }
 }

and since the package is the same, that's the same as 而且由于包装相同,因此与

 package main {
     use warnings;
     use strict;
     {
     # ...
     }
 }

In other words the package is main at the beginning of the file and an implicit block scope (the file scope) is open. 换句话说,该包在文件的开头是main ,并且一个隐式块作用域(文件作用域)已打开。 When you re-enter main package, it has no effect and if it is associated with block, it behaves as any block. 当您重新输入main包时,它没有任何作用,并且如果它与block相关联,它的行为就像任何block。

Scope and execution order have little to do with each other. 范围和执行顺序彼此无关。

Yes, the default package is main . 是的,默认软件包是main So it could be said that 所以可以

---- begin file ----
1: #!/usr/bin/perl
2: my $var;
3: ...;
---- end file ----

is equivalent to 相当于

package main {
---- begin file ----
1: #!/usr/bin/perl
2: my $var;
3: ...;
---- end file ----
}

It is simply that the main package is assumed unless another is specified. 除非指定了其他main软件包,否则仅假定main软件包。 This does not change line numbers etc. 这不会更改行号等。

When a variable declaration is encountered, it is immediately added to the list of known variables. 遇到变量声明时,它将立即添加到已知变量列表中。 Or more precisely, as soon as the statement where it was declared has ended: 或更准确地说,一旦声明所在的语句结束,就:

my      # $var unknown
$var    # $var unknown
=       # $var unknown
foo()   # $var unknown
;       # NOW $var is declared

Similar for pragmas: An use statement is executed as soon at is fully parsed. 对于编译指示类似:完全解析后立即执行use语句。 In the next statement, all imports are available. 在下一条语句中,所有导入均可用。

Blocks like BEGIN are executed outside of the normal control flow, but obey scoping rules. BEGIN这样的块是在常规控制流之外执行的,但要遵循作用域规则。

BEGIN blocks are executed as soon as they are fully parsed. BEGIN块在完全解析后立即执行。 The return value is discarded. 返回值将被丢弃。

END blocks are executed when the interpreter exits by normal means. 当解释器以正常方式退出时,将执行END块。

When we have 当我们有

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;
}

The result? 结果?

42
1

Note that if I do not assign a new value at runtime, this variable keeps its compile time value: 请注意,如果我在运行时未分配新值,则此变量将保留其编译时值:

my $var;
...; # rest as before

Then we get 然后我们得到

42
42

Blocks can be arbitrarily nested: 块可以任意嵌套:

my $var;
if (0) {
  BEGIN {
    say "BEGIN 1: ", ++$var;
    BEGIN {
      say "BEGIN 2: ", ++$var;
      BEGIN { $var = 0 }
    }
  }
}

Output: 输出:

BEGIN 2: 1
BEGIN 1: 2

Here we can see that BEGIN blocks are executed before the if (0) is optimized away, because BEGIN is executed immediately . 在这里我们可以看到BEGIN块是在if (0)被优化之前执行的,因为BEGIN是立即执行的。

We can also ask which package a block is in: 我们还可以询问一个块位于哪个包中:

BEGIN { say "BEGIN: ", __PACKAGE__ }
say "before package main: ", __PACKAGE__;

# useless redeclaration, we are already in main
package main {
  say "in package main: ", __PACKAGE__;
}

Output: 输出:

BEGIN: main
before package main: main
in package main: main

So we are in main before we redeclared it. 因此,在重新声明之前,我们已经处于main地位。 A package is no sealed, immutable entity. 包不是密封的,不变的实体。 It is rather a namespace we can reenter at will: 它是一个我们可以随意重新输入的名称空间:

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__ }
  }
}

Output: 输出:

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

So regarding this: 因此,关于此:

The question is - is here ANY benefit using something like: 现在的问题是-在这里使用像任何益处:

 ---- begin of the file --- use strict; use warnings; package main { my $var; } 

The answer is no : If we are already in the package main , redeclaring it has no benefit: 答案是否定的 :如果我们已经在包main ,则重新声明它没有好处:

say __PACKAGE__;
package main {
  my $var;
  say __PACKAGE__;
}
say __PACKAGE__;

If we execute that we can see we are in main the whole time. 如果执行,我们就能看到我们始终处于main状态。

Pragmas like strict and warnings have lexical scope, so declaring them as early as possible is good. 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;

Output: 输出:

Global symbol "$var" requires explicit package name at - line 8.
BEGIN not safe after errors--compilation aborted at - line 10.

The variable was not declared inside the BEGIN block, because it was compiled and (not quite executed) before the declaration. 该变量未在BEGIN块内声明,因为它已在声明之前进行编译(且执行不充分)。 Therefore, strict issues this error. 因此, strict发出此错误。 Because this error occurred during compilation of the BEGIN block, this block wasn't executed. 由于在BEGIN块的编译期间发生了此错误,因此未执行该块。

Because of scoping, you can't always reorder your source code in a way that avoids using BEGIN blocks. 由于作用域,您不能总是以避免使用BEGIN块的方式对源代码进行重新排序。 Here is something you should never do: 这是您永远不应该做的事情:

for (1 .. 3) {
  my $var;
  BEGIN { $var = 42 };
  say $var // "undef";
}

Output: 输出:

42
undef
undef

because $var is emptied whenever the block is left. 因为只要离开该块,就会清空$var (This is probably undefined behaviour, and may possibly change. This runs under at least v5.16.3 and v5.14.2). (这可能是不确定的行为,并且可能会更改。至少在v5.16.3和v5.14.2下运行)。

When your program is compiled no reordering takes place. 编译程序时,不会进行任何重新排序。 Instead, BEGIN blocks are executed as soon as they are compiled. 相反,BEGIN块在编译后立即执行。

For the exact times when CHECK and END are run, read through perlmod . 有关运行CHECK和END的确切时间,请阅读perlmod

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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