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