簡體   English   中英

Perl - 從 BEGIN 塊中復制變量值

[英]Perl - copy variables value out of BEGIN block

我有一個簡單的腳本:

our $height = 40;
our $width = 40;

BEGIN {
    GetOptions( 'help' => \$help,           
                'x=i' => \$width,
                'y=i' => \$height) or die "No args.";


    if($help) { 
        print "Some help";   
        exit 0;
    }

    print $width."\n"; #it is 10 when call with script.pl -x 10 -y 10
    print $height."\n"; #it is 10 when call with script.pl -x 10 -y 10

    #some other code which check installed modules

    eval 'use Term::Size::Any qw( chars pixels )';
    if ( $@ ) {
        if ( $@ =~ /Cant locate (\S+)/ ) {
            warn "No modules";
            exit 2;
        }
    }


}

print $width."\n"; #but here is still 40 not 10
print $height."\n";#but here is still 40 not 10

我用 2 個參數(x 和 y)調用這個腳本,例如:script.pl -x 10 -y 10。但是給定的值沒有保存在變量 $width 和 $height 中。 我想通過給出參數來改變這個變量。 如何復制給定值或將它們保存到$width$height 是否可以?

編輯- 我在這個例子中添加了一些代碼

BEGIN子句正常代碼之前執行。 聲明$height$width處理選項后將它們設置為 40。

解決方案:處理BEGIN子句之外的選項。

問題是像our $height = 40等聲明/定義是分兩個階段執行的。 聲明在編譯時執行,而賦值在運行時完成。 這意味着類似

my $x = 0;

BEGIN {
    $x = 1;
}

say $x;

將顯示0 ,因為$x在編譯時聲明並在編譯時由於BEGIN塊而設置為 1 。 但它在運行時被設置為零。

您只需將聲明/定義更改為聲明即可。 這樣就不會在運行時修改BEGIN塊所做的分配

use strict;
use warnings 'all';
use feature 'say';

my $xx;

BEGIN {
    $xx = 1;
}

say $xx;

輸出

1

請注意,不需要our . my的幾乎總是可取的。 並且請不要使用BEGIN塊來執行重要的代碼塊:它們應該保留用於類似於在運行時開始之前加載所需模塊的准備操作。 沒有人希望程序在無法編譯時輸出幫助文本,而這正是您想要做的。

所有BEGIN塊都在編譯階段執行,盡快(在它們被解析之后)——甚至在運行階段開始之前。 在 perlmod 中查看此內容並查看這篇“Effective Perler”文章 另外, my $x = 1;的聲明部分my $x = 1; 也發生在編譯階段,但分配是在運行時完成的。

因此聲明了$height$weight ,然后處理選項的代碼在其BEGIN塊中運行,一旦解釋器進入運行階段,變量被分配40 ,覆蓋在該BEGIN塊中分配的任何內容。

因此,一種解決方法是BEGIN塊之前聲明這些變量,而無需賦值,如果變量仍未定義(我假設為默認值),則在BEGIN塊之后分配40

但是,最好不要在BEGIN塊中處理選項或進行任何此類大量工作。

這里有一些其他方法可以滿足您的需求。

在編譯期間加載模塊很適合您的目的,只要您在運行時知道它是否有效。 因此,在BEGIN塊中的eval下按您的方式加載它,以便您可以設置一個標志供以后使用(有條件地)。 這個標志需要在那個BEGIN塊之前聲明(沒有賦值)。

my $ok_Term_Size_Any;

BEGIN { 
    eval 'use Term::Size::Any qw(chars pixels)';
    $ok_Term_Size_Any = 1 unless $@;
};

# use the module or else, based on $ok_Term_Size_Any

聲明發生在編譯時,並且在BEGIN也是如此 - 在條件if not $@ 如果該條件失敗(無法加載模塊),則賦值不會發生並且變量保持未定義狀態。 因此,它可以用作進一步處理中的標志。

另外:雖然沒有顯示其余的代碼,但我無法想象需要our ; my代替。


注意請參閱此問題以了解有關以下方法的細微之處

或者,在運行時加載所有“棘手”模塊。 然后解析選項沒有問題,現在可以在運行時正常完成,在這些模塊之前或之后,視情況而定。

use Module qw(LIST); 聲明正是

BEGIN {
    require Module;
    Module->import(LIST);
};

請參閱使用 因此,要在運行時檢查模塊,在使用它之前,請運行並評估該代碼

use warnings 'all';
use strict;

eval {
    require Module;
    Module->import( qw(fun1 fun2 ...) );
};
if ($@) {
    # Load an alternative module or set a flag or exit ...
};

# use the module or inform the user based on the flag

可以使用Try::Tiny而不是使用eval (帶有必要的錯誤檢查),但請注意,這也存在問題。 請參閱此帖子,也可了解有關選擇的討論。 使用模塊而不是eval -and- $@的硬性原因已 在 5.14 中解決


暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM