Scroll to navigation

PERLFAQ7(7) Perl Programmers Reference Guide PERLFAQ7(7)


NAME

perlfaq7 - 綜合的問題 (2003/07/24 02:17:21)

DESCRIPTION 描述

本節討論綜合的 Perl 語言問題,不適於在其他所有段落中討論的問題

我能拿到 Perl的 BNF/yacc/RE嗎?

沒有 BNF, 但是你可以從源代碼的 perly.y 文件的 yacc 語法中自行歸納,如果你足夠勇敢的話。語法依賴於非常智能的詞法分析,因此也要準備好閱讀 toke.c。

用 Chaim Frenkel的話:"Perl的語法無法被簡化到可以用 BNF 表示。解析Perl的工作是分散於 yacc、lexer、煙霧和鏡子之間。"

$@%*這些符號是什麼意思?我怎麼知道何時該使用他們呢?

它們都是類型限定符號,在 perldata 中詳述:

    $ 標量值,數字,字符串或引用
    @ 數組
    % 散列,關聯數組
    & 子程序,也就是函數,過程,方法
    * 代表這個符號的所有類型。在版本4中,可以用作指針,但是在新的 perl 中可以只用引用就可以了

有些其他的符號你可能會碰到但卻不是指定形態用的有:

    <> 這是用來從一個文件句柄裏輸入一份記錄
    \ 取某樣東西的引用

注意 <FILE> 不是用來指定文件類型,亦非此句柄的名字。它只是 將<>這個運算符作用在 FILE這個句柄上。在標量上下文 (scalar context) 中,它自 FILE 把手一次讀入一行 (嗯,該說一筆記錄,參看 $/),在序列情境 (list context)下,則一次將 全部的內容讀 入。當對檔案使用開、關或其它 <>之外的動作、或甚至只是提到把 手時,切記不要使用 <>。下面的用法是正確的:"eof(FH)", "seek(FH, 0, 2)" 以及 "copying from STDIN to FILE".

字串加引號或使用分號及逗號是否絕對必要/還是完全沒必要?

通常一個沒有冠上形態符號的字 (bareword)是不需被納入引號裏的,但在大多數的情況下或許該這麼做 (在 "use strict" 下則是必須的)。但由一個簡單的字(不能是一個已定義的副函數之名稱)所構成的索引值,和 "=>" 左端的運算子,都會被視爲已納入引號了:

    這些                     和這些一樣
    ------------            ---------------
    $foo{line}              $foo{"line"}
    bar => stuff            "bar" => stuff

一個區塊末端的分號可有可無,一個序列的最後一個逗號亦同。良好的寫作風格 (參看perlstyle)中建議除了在單行程式 (one-liners)的情況外都將他們加上去:

    if ($whoops) { exit 1 }
    @nums = (1, 2, 3);

    if ($whoops) {
        exit 1;
    }
    @lines = (
        "There Beren came from mountains cold",
        "And lost he wandered under leaves",
    );

我如何跳過一些傳回值?

一種方法是將傳回值當作序列來對待,然後用索引來指名其中的某個位置:

        $dir = (getpwnam($user))[7];

另一種方法就是在等號左端用 undef 作元素:

    ($dev, $ino, undef, undef, $uid, $gid) = stat($file);

也可以用一個列表片段來僅選擇你需要的元素:

        ($dev, $ino, $uid, $gid) = ( stat($file) )[0,1,4,5];

我如何暫時濾掉警告訊息?

如果正在運行 Perl 5.6.0 或更高版本, "use warnings" 編用可以對警告如何產生進行很好的控制。參見 perllexwarn 中的細節

    {
        no warnings;          # 暫時關掉警告訊息
        $a = $b + $c;         # 我知道這些變數可能未定義
    }

如果運行舊版本的 Perl,變量 $^W (在 perlvar 中有記載) 控制了這個塊的運行時警告:

    {
        local $^W = 0;        # 暫時關掉警告訊息
        $a = $b + $c;         # 我知道這些變數可能未定義
    }

注意,像所有的標點符號變數一樣,目前不能對 $^W 用 my(),只能用 local()。

什麼是一個擴充?

一種從 Perl呼叫編譯好的 C程式碼的方法。閱讀 perlxstut是個多瞭解擴充(extensions)的好方法。

爲何 Perl運算子的優先順序和 C的不一樣?

事實上它們是相同的。所有 Perl自 C借過來的運算子都具備與原來在 C 中相同的優先順序。問題出在那些 C沒有的運算子,特別是那些將其右方一律當成序列情境對待的函數,例如 print, chmod, exec等等。這類的函數被稱作序列運算子("list operators"),在 perlop的優先順序表中就是這麼稱呼。

一個常犯的錯誤像是:

    unlink $file ⎪⎪ die "snafu";

這會被解譯器看成是:

    unlink ($file ⎪⎪ die "snafu");

要避免此問題,須加上括號或是用超低優先的 "or" 運算子:

    (unlink $file) ⎪⎪ die "snafu";
    unlink $file or die "snafu";

這些“英文的”運算子 (and, or, xor,及 not)是刻意設計成較一般序列運算子低的優先順序,這就是爲了解決前述的狀況。

另一個擁有出人意料的優先順序者爲指數。它甚至高於負號,這使得 "-2**2"變成負四而非正四。他同時也會“向右靠”(right-associate),意思是說 "2**3**2" 代表二的九次方,而不是八的平方。

Although it has the same precedence as in C, Perl's "?:" operator produces an lvalue. This assigns $x to either $a or $b, depending on the trueness of $maybe:

    ($maybe ? $a : $b) = $x;

我如何聲明/創建一個數據結構?

一般來說,我們不 ``聲明'' 一個結構。用一個 (通常是匿名的) 散列的引用 (hash reference)即可。參看 perlref 以及 perldsc,裏面有更多資料。以下是一個範例:

    $person = {};                   # new anonymous hash
    $person->{AGE}  = 24;           # set field AGE to 24
    $person->{NAME} = "Nat";        # set field NAME to "Nat"

如果你要的是更嚴謹的寫法,看看 perltoot 。

如何創建一個模塊?

一個模組就是一個放在同名檔案裏的包裹(package)。例如,Hello::There模組會放在Hello/There.pm。perlmod 裏有詳盡說明。Exporter 也會很有幫助。如果你正在寫一個 C 或是混合了 C及 Perl 的模組,那麼你就該讀 perlxstut 。

The "h2xs" program will create stubs for all the important stuff for you:

  % h2xs -XA -n My::Module

The "-X" switch tells "h2xs" that you are not using "XS" extension code. The "-A" switch tells "h2xs" that you are not using the AutoLoader, and the "-n" switch specifies the name of the module. See h2xs for more details.

如何創建一個類?

perltoot 裏面有對於類和對象的介紹, perlobj 和 perlbot 也有。

如何知道一個變量是否是污染的?

可以使用 Scalar::Util 模塊中的 tainted() 函數 (可從 CPAN 獲取,也包含在 Perl 5.8.0 中)。參見 perlsec 中的 "Laundering and Detecting Tainted Data" 。

什麼是閉包?

關於閉包的說明,請看 perlref 。

閉包 (closure)是個精確但又很難解釋的計算機科學名詞。在 Perl 裏面,閉包是以匿名函數的形式來實現,具有持續參照位於該函數範圍之外的文字式變數值的能力。這些外部的文字變數會神奇地保留它們在閉包函數最初定義時的值 (深連結)。

如果一個程式語言容許函數遞迴另一個函數的話 (像 Perl 就是),閉包便具有意義。要注意的是,有些語言雖提供匿名函數的功能,但卻無法正確處理閉包; Python 這個語言便是一例。如果要想多瞭解閉包的話,建議你去找本功能性程式設計的教科書來看。Scheme這個語言不僅支援閉包,更鼓勵多加使用。

以下是個典型的產生函數的函數:

    sub add_function_generator {
      return sub { shift + shift };
    }

    $add_sub = add_function_generator();
    $sum = $add_sub->(4,5);                # $sum is 9 now.

閉包用起來就像是個 函數樣板,其中保留了一些可以在稍後再填入的空格。 add_function_generator() 所遞迴的匿名函數在技術上來講並不能算是一個閉包,因爲它沒有用到任何位在這個函數範圍之外的文字變數。

把上面這個例子和下面這個 make_adder()函數對照一下,下面這個函數所遞迴的匿名函數中使用了一個外部的文字變數。這種指名外部函數的作法需要由 Perl遞迴一個適當的閉包,因此那個文字變數在匿名函數產生之時的值便永久地被鎖進閉 包裏。

    sub make_adder {
        my $addpiece = shift;
        return sub { shift + $addpiece };
    }

    $f1 = make_adder(20);
    $f2 = make_adder(555);

這樣一來 "&$f1($n)" 永遠會是 20加上你傳進去的值 $n ,而 "&$f2($n)" 將 永遠會是 555加上你傳進去的值 $n。$addpiece 的值會在閉包中保留下來。

閉包在比較實際的場合中也常用得到,譬如當你想把一些程式碼傳入一個函數時:

    my $line;
    timeout( 30, sub { $line = <STDIN> } );

如果要執行的程式碼當初是以字串的形式傳入的話,即 '$line = <STDIN>' ,那麼 timeout() 這個假想的函數在回到該函數被呼叫時所在的範圍後便無法再擷取 $line 這個文字變數的值了。

什麼是變量自殺,我應該怎樣防止它?

變數自殺指的是 (暫時或是永久)地失去一個變數的值。造成這個現象的原因是做範圍界定的 my() 和 local()和閉包或 foreach()迴圈變數及函數參數相互影響 所致。過去很容易偶爾丟失變量,現在就困難多了,可以試試這段代碼:

    my $f = "foo";
    sub T {
      while ($i++ < 3) { my $f = $f; $f .= "bar"; print $f, "\n" }
    }
    T;
    print "Finally $f\n";

有叄個 "bar" 加進去的 $f 變數應該是一個新的 $f (因爲 "my $f" 在每個循環都應該創造一個新的區域變數)。然而,實際上並非如此。這個臭蟲最新的 Perl 版本中已被修正 (在 5.004_05, 5.005_03 和 5.005_56 上測試過)。

如何傳遞/返回一個{函數 Function, 文件句柄 FileHandle, 數組 Array,散列 Hash, 方法 Method, 正則表達式 Regex}?

除了正規表現式這個特例外,你需要以傳參考值的方式傳資料給這些物件。參看 perlsub 中的 "Pass by Reference",裏面有針對此問題的討論,以及 perlref 裏面有引用的資訊。

參見下面的 ``Passing Regexes'',學習如何傳遞正則表達式。

傳遞變量和函數
一般的變數和函數是相當簡單的:只要傳一個指向現存的匿名變數或函數的參考值即可:

    func( \$some_scalar );
    

    func( \@some_array  );
    func( [ 1 .. 10 ]   );
    

    func( \%some_hash   );
    func( { this => 10, that => 20 }   );
    

    func( \&some_func   );
    func( sub { $_[0] ** $_[1] }   );
    
傳遞文件句柄
在 Perl5.6 中,你可以用標量變量表示文件句柄,並將它與其他標量同樣處理

        open my $fh, $filename or die "Cannot open $filename! $!";
        func( $fh );
    

        sub func {
                my $passed_fh = shift;
    

                my $line = <$fh>;
                }
    

在 Perl5.6 之前,必須用 *FH"\*FH" 語法。這叫做 "typeglobs"--參見 perldata 中的 "Typeglobs and Filehandles" 和 perlsub 中的 "Pass by Reference"。

傳遞正則表達式
要傳遞正則表達式,你需要使用足夠新的 Perl 發行,足以支持 "qr//" 構造方式的版本,傳遞字符串,使用一個捕獲異常的 eval,或者其他更聰明的辦法。

這裏有一個如何傳遞正則表達式字符串的例子,使用 "qr//":

    sub compare($$) {
        my ($val1, $regex) = @_;
        my $retval = $val1 =~ /$regex/;
        return $retval;
    }
    $match = compare("old McDonald", qr/d.*D/i);
    

注意 "qr//" 如何允許在後面加上標誌。這個模式在編譯期被編譯,儘管它後來才執行。 "qr//" 表示法雖然好用,但是直到 5.005 發行中才引入。在那之前,你必須用不直觀的辦法。例如,如果沒有 "qr//" 的話:

    sub compare($$) {
        my ($val1, $regex) = @_;
        my $retval = eval { $val1 =~ /$regex/ };
        die if $@;
        return $retval;
    }
    

    $match = compare("old McDonald", q/($?i)d.*D/);
    

確保你沒有任何這樣的東西:

    return eval "\$val =~ /$regex/";   # WRONG
    

否則別人會靠雙引號括起來的字串以及 eval 雙重解譯的本質而偷偷插入 shell指令來作壞事。例如:

    $pattern_of_evil = 'danger ${ system("rm -rf * &") } danger';
    

    eval "\$string =~ /$pattern_of_evil/";
    

想學非常非常聰明的方法的讀者可以參考 O'Reilly 出的 Mastering Regular Expressions這本書,作者是 Jeffrey Friedl。其中第 273頁的 Build_MatchMany_Function()特別的有趣。在 perlfaq2中可以找到有關本書 的資料。

傳遞方法
要傳遞一個對象方法給一個函數,可以這樣做:

    call_a_lot(10, $some_obj, "methname")
    sub call_a_lot {
        my ($count, $widget, $trick) = @_;
        for (my $i = 0; $i < $count; $i++) {
            $widget->$trick();
        }
    }
    

或者,使用一個閉包來包含這個對象,它的方法調用及參數:

    my $whatnot =  sub { $some_obj->obfuscate(@args) };
    func($whatnot);
    sub func {
        my $code = shift;
        &$code();
    }
    

也可以研究 UNIVERSAL 類別中的 can()方法 (附於標準 Perl 版本中)。

How do I create a static variable?

就像與 Perl相關的其他事情一樣,``條條大路通羅馬'' (TMTOWTDI)。對其他語言來說叫做 ``靜態變數'' (static variable)的東西,在 Perl裏面可能是一個函數私有的變數(只有該函數自己看得到,且在不同的呼叫間保持定值),或是一個檔案私有(file-private)變數(只有同一個檔案中的函數纔看得到)。

以下就是實作函數私有變數的程式:

    BEGIN {
        my $counter = 42;
        sub prev_counter { return --$counter }
        sub next_counter { return $counter++ }
    }

prev_counter() 和 next_counter() 將會共用一個於編譯時初始化的私有變數 $counter。

要聲明一個檔案私有(file-private)變數,你仍然得使用 my(),將它放在檔案開頭處最外圍。假設現在是在 Pax.pm 這個檔案裏:

    package Pax;
    my $started = scalar(localtime(time()));

    sub begun { return $started }

當用 "use Pax""require Pax" 載入此模組時,這個變數就會被初始化。不過它不會被資源回收,像其他出了有效範圍的變數那樣,因爲 begun()函數要用到它,但是沒有其他函數能擷取它。這個變數不能以 $Pax::started 的形式來擷取,因爲它所存在的範圍與此包裹無關。它存在的範圍是這個檔案。可想見地,一個檔案裏可以放好幾個包裹,而所有的包裹都擷取同一個私有變數,但從另一個檔案中,即使是屬於同一個包裹(package),也不能取得它的值。

參見 perlsub 中的 "Persistent Private Variables" 的細節.

What's the difference between dynamic and lexical (static) scoping? Between local() and my()?

local($x) 將全域變數 $x的原值存起來,並在此函數執行期間賦予一個新 值,此值可以從此函數所呼叫的其他函數裏看見。這整個步驟是在執行期間完成的,所以才叫做動態範圍選取 (dynamic scoping)。local()影響的是全域變數,或者稱作包裹變數或動態變數。

"my($x)" 會創造一個只能在目前這個函數裏看得見的新變數。這個步驟是在編譯期完成(compile-time),所以稱作文字式或是靜態範圍選取。my()總是作用在私有變數,也稱作文字式變數或(不當地)稱作靜態(範圍選取)變數。

例如:

    sub visible {
        print "var has value $var\n";
    }

    sub dynamic {
        local $var = 'local';   # 爲全局變量暫時賦值
        visible();              # 調用 $var 變量
    }

    sub lexical {
        my $var = 'private';    # 新的私有變量 $var
        visible();              # (在 sub 作用域之外不可見)
    }

    $var = 'global';

    visible();                  # prints global
    dynamic();                  # prints local
    lexical();                  # prints global

你可以發現在整個過程中 ``private''這個值都印不出來。那是因爲 $var的值只存在於lexical() 函數的區塊裏面,對它所呼叫的函數來說是看不到的。

總結來說,local()不會產生你想像中的私有、區域變數。它只是將一個暫時的值授予一個全域變數。如果你要的是私有的變數,那麼 my() 纔是你要找的。

參見 perlsub 中的 "Private Variables via my()" 以及 "Temporary Values via local()" 來獲取詳情

在存在同名內部變量的作用域中,如何存取一個動態變量?

如果你知道你所在的是哪一個包裹(package)的話,你可以直接指名,就像寫 $Some_Pack::var 這樣。注意 $::var 這個寫法 並非表示目前此包裹 (package) 內的動態變數 $var,而是指在 main包裹(package) 裏的那個,就等價於 $main::var

        use vars '$var';
        local $var = "global";
        my    $var = "lexical";

        print "lexical is $var\n";
        print "global  is $main::var\n";

可選的,可以使用編譯器指令 our() 來在當前靜態作用域中引入動態變量

        require 5.006; # our() did not exist before 5.6
        use vars '$var';

        local $var = "global";
        my $var    = "lexical";

        print "lexical is $var\n";

        {
          our $var;
          print "global  is $var\n";
        }

深連接和淺連接有什麼不同?

在深連結中,匿名函數中所用到的文字式變數值是以該函數產生時所在的範圍爲準。在淺連結中,這些變數值是以函數被呼叫時所在的範圍爲準,如果在這個範圍中恰巧有同名的變數,便使用這些當地變數的值。Perl總是使用文字式變數(就是以 my()創造的)式的深連結。然而,動態變數(也稱作全域(global),區域(local),或包裹(package)變數)在功效上是淺連結。就把這當作是少用它們的另一個理由好 了。請參考 "什麼是閉包" 一節。

爲什麼

local()會把 =號右邊以序列情境來對待。而 <FH> 這個閱讀的 動作,就像 Perl裏許多的函數以及運算子一樣,會自動分辨出自己被呼叫時所在的情境並且採取適當的作法。一般來說,scalar()函數可以幫點忙。這個函數實際上對資料本身不會有任何作用(與一般所認爲的相反),但是會告訴它所作用的函數要以對待純量值的方法來運算。如果那個函數沒有預先定義好碰到純量情境的行爲,那麼它當然也幫不了你(例如 sort() 函數)。

然而,在以上這個例子 (local...)中,只要省略括號便可強制使用標量情境:

    local($foo) = <FILE>;           # WRONG
    local($foo) = scalar(<FILE>);   # ok
    local $foo  = <FILE>;           # right

其實在這個例子中,或許你該改用文字式變數 (lexical variables),不過會碰到 的問題跟上面一樣:

    my($foo) = <FILE>;  # WRONG
    my $foo  = <FILE>;  # right

如何重定義一個內建函數,操作符 或者方法?

爲什麼要這麼做? :-)

如果你要覆蓋掉某個內建函數,例如說 open(),那你得將其定義從另一個模組載 入。參考 perlsub 中的 Overriding Builtin Functions。在 "Class::Template" 裏面也有個範例。

如果你要覆蓋掉一個 Perl運算子,像是 "+""**", 那你該使用 "use overload" 這個編用,在 overload 中有記載。

如果你要覆蓋父類別 (parent class)裏的方法呼叫 (method calls),請看 perltoot 中的 Overridden Methods 。

調用函數時 &foo 和 foo() 的形式有什麼不同?

當你用 &foo的方式呼叫一個函數時,你等於讓這個函數擷取你目前 @_裏面的值,同時也跳過原型定義 (prototypes)不用。這表式此函數抓到的是你當時的 @_, 而非一個空的 @_!雖然嚴格講起來它也不能算是個 bug (但是在 perlsub裏面是這麼說的)但在大部份情況下,這也算不上是個特別功能。

當你用 &foo()的方式呼叫你的函數時,你會得到一個新的 @_,但是原型定義 仍然會被避開不用。

在一般情況下,你該用 foo()的方式去呼叫函數。只有在編譯器已事先知道這個函數的定義時,括號才能省略,譬如當這個函數所在的模組或包裹被 use (但如果是被 require則不行)時,或是透過先前提及或 use subs宣告等方法,讓編譯器先接觸到這個函數的定義。用這種呼叫方式,即使是當括號省掉時,你都會得到一個乾淨的 @_,不會有任何不該出現的舊值殘留在上面。

如何創建一個分支語句?

這個問題在 perlsyn 文件裏有更詳盡的解釋。簡單來說,因爲 Perl本身已提供了多種不同的條件測試方法可供使用 (數值比較、字串比較、 glob比較、正規表示式 對應、覆蓋比較,及其它),所以並沒有正式的 case敘述語法。雖然自 perl1起這就一直是許多人期盼的一個項目,但因 Larry無法決定怎樣纔是呈現這功能的最好方法,因此還是將它略掉。

從 Perl 5.8 開始,要使用 swtich 和 case,可以使用 Switch 擴展,就是這樣:

        use Switch;

此後就可以用 switch 和 case 了. It is not as fast as it could be because it's not really part of the language (it's done using source filters) but it is available, and it's very flexible.

But if one wants to use pure Perl, the general answer is to write a construct like this:

    for ($variable_to_test) {
        if    (/pat1/)  { }     # do something
        elsif (/pat2/)  { }     # do something else
        elsif (/pat3/)  { }     # do something else
        else            { }     # default
    }

下面這個簡單的 switch範例以模式對應爲基礎。我們將要做的是對儲存在 $whatchamacallit裏面的參考值 (reference)的類型進行多重條件的判斷。【譯註:$whatchamacallit 函意爲 $what_you_might_call_it】

    SWITCH: for (ref $whatchamacallit) {

        /^$/            && die "not a reference";

        /SCALAR/        && do {
                                print_scalar($$ref);
                                last SWITCH;
                        };

        /ARRAY/         && do {
                                print_array(@$ref);
                                last SWITCH;
                        };

        /HASH/          && do {
                                print_hash(%$ref);
                                last SWITCH;
                        };

        /CODE/          && do {
                                warn "can't print function ref";
                                last SWITCH;
                        };

        # DEFAULT

        warn "User defined type skipped";

    }

See "perlsyn/"Basic BLOCKs and Switch Statements"" for many other examples in this style.

Sometimes you should change the positions of the constant and the variable. For example, let's say you wanted to test which of many answers you were given, but in a case-insensitive way that also allows abbreviations. You can use the following technique if the strings all start with different characters or if you want to arrange the matches so that one takes precedence over another, as "SEND" has precedence over "STOP" here:

    chomp($answer = <>);
    if    ("SEND"  =~ /^\Q$answer/i) { print "Action is send\n"  }
    elsif ("STOP"  =~ /^\Q$answer/i) { print "Action is stop\n"  }
    elsif ("ABORT" =~ /^\Q$answer/i) { print "Action is abort\n" }
    elsif ("LIST"  =~ /^\Q$answer/i) { print "Action is list\n"  }
    elsif ("EDIT"  =~ /^\Q$answer/i) { print "Action is edit\n"  }

A totally different approach is to create a hash of function references.

    my %commands = (
        "happy" => \&joy,
        "sad",  => \&sullen,
        "done"  => sub { die "See ya!" },
        "mad"   => \&angry,
    );

    print "How are you? ";
    chomp($string = <STDIN>);
    if ($commands{$string}) {
        $commands{$string}->();
    } else {
        print "No such command: $string\n";
    }

如何捕獲對未定義變量,函數或方法的訪問?

在 perlsub 中的 "Autoloading" 和 perltoot 中的 "AUTOLOAD: Proxy Methods" 裏 提到的 AUTOLOAD 方法讓你能捕捉對於未定義函數與方法的呼叫。

When it comes to undefined variables that would trigger a warning under "use warnings", you can promote the warning to an error.

        use warnings FATAL => qw(uninitialized);

爲什麼找不到包含在同一個文件中的方法?

一些可能的原因:你用的繼承給搞混了、你拼錯了該方法的名字,或是物件的類別錯誤。這些事在 perltoot裏都有更詳盡的說明。同時你也可以用 "print ref($object)" 來找出 $object 這個物件是被歸到哪個類別底下。

另一個可能的原因是你在 Perl還不知道這個包裹 (package)存在之前便將某個類別名稱在間接式物件語法中使用 (例如 "find Guru "Samy"")。最好是在開始使用你的包裹前,先確定都已經先把它們定義好了,如果你用的是 use 而非 require的話,這件事便會自動處理好。不然的話,確定你使用箭頭式語法 (例如,"Guru->find("Samy")"))。在perlobj 裏面對於物件的記號有詳盡解釋。

Make sure to read about creating modules in perlmod and the perils of indirect objects in "Method Invocation" in perlobj.

如何找到當前的包?

如果只是一個隨意的程式的話,你可以用下面的方法找出目前正被編譯的包裹爲何:

    my $packname = __PACKAGE__;

但如果是一個方法的話,而且印出的錯誤訊息中要包含呼叫此方法的物件 (不見得就是把這個方法編譯進去的那個物件)則:

    sub amethod {
        my $self  = shift;
        my $class = ref($self) ⎪⎪ $self;
        warn "called me from a $class object";
    }

如何註釋掉大塊的 perl 代碼?

用內嵌 POD格式的方法把程式碼變註解。將要註釋掉的塊包含在 POD 標記內, 例如 "=for nobody""=cut" (標誌着 POD 塊的結束).

    # 這是程式

    =for nobody

    all of this stuff

    接下來此處所有的文字都會被忽略

    =cut

    # program continues

The pod directives cannot go just anywhere. You must put a pod directive where the parser is expecting a new statement, not just in the middle of an expression or some other arbitrary grammar production.

See perlpod for more details.

How do I clear a package?

Use this code, provided by Mark-Jason Dominus:

    sub scrub_package {
        no strict 'refs';
        my $pack = shift;
        die "Shouldn't delete main package"
            if $pack eq "" ⎪⎪ $pack eq "main";
        my $stash = *{$pack . '::'}{HASH};
        my $name;
        foreach $name (keys %$stash) {
            my $fullname = $pack . '::' . $name;
            # Get rid of everything with that name.
            undef $$fullname;
            undef @$fullname;
            undef %$fullname;
            undef &$fullname;
            undef *$fullname;
        }
    }

Or, if you're using a recent release of Perl, you can just use the Symbol::delete_package() function instead.

How can I use a variable as a variable name?

Beginners often think they want to have a variable contain the name of a variable.

    $fred    = 23;
    $varname = "fred";
    ++$$varname;         # $fred now 24

This works sometimes, but it is a very bad idea for two reasons.

The first reason is that this technique only works on global variables. That means that if $fred is a lexical variable created with my() in the above example, the code wouldn't work at all: you'd accidentally access the global and skip right over the private lexical altogether. Global variables are bad because they can easily collide accidentally and in general make for non-scalable and confusing code.

Symbolic references are forbidden under the "use strict" pragma. They are not true references and consequently are not reference counted or garbage collected.

The other reason why using a variable to hold the name of another variable is a bad idea is that the question often stems from a lack of understanding of Perl data structures, particularly hashes. By using symbolic references, you are just using the package's symbol-table hash (like %main::) instead of a user-defined hash. The solution is to use your own hash or a real reference instead.

    $USER_VARS{"fred"} = 23;
    $varname = "fred";
    $USER_VARS{$varname}++;  # not $$varname++

There we're using the %USER_VARS hash instead of symbolic references. Sometimes this comes up in reading strings from the user with variable references and wanting to expand them to the values of your perl program's variables. This is also a bad idea because it conflates the program-addressable namespace and the user-addressable one. Instead of reading a string and expanding it to the actual contents of your program's own variables:

    $str = 'this has a $fred and $barney in it';
    $str =~ s/(\$\w+)/$1/eeg;             # need double eval

it would be better to keep a hash around like %USER_VARS and have variable references actually refer to entries in that hash:

    $str =~ s/\$(\w+)/$USER_VARS{$1}/g;   # no /e here at all

That's faster, cleaner, and safer than the previous approach. Of course, you don't need to use a dollar sign. You could use your own scheme to make it less confusing, like bracketed percent symbols, etc.

    $str = 'this has a %fred% and %barney% in it';
    $str =~ s/%(\w+)%/$USER_VARS{$1}/g;   # no /e here at all

Another reason that folks sometimes think they want a variable to contain the name of a variable is because they don't know how to build proper data structures using hashes. For example, let's say they wanted two hashes in their program: %fred and %barney, and that they wanted to use another scalar variable to refer to those by name.

    $name = "fred";
    $$name{WIFE} = "wilma";     # set %fred

    $name = "barney";
    $$name{WIFE} = "betty";     # set %barney

This is still a symbolic reference, and is still saddled with the problems enumerated above. It would be far better to write:

    $folks{"fred"}{WIFE}   = "wilma";
    $folks{"barney"}{WIFE} = "betty";

And just use a multilevel hash to start with.

The only times that you absolutely must use symbolic references are when you really must refer to the symbol table. This may be because it's something that can't take a real reference to, such as a format name. Doing so may also be important for method calls, since these always go through the symbol table for resolution.

In those cases, you would turn off "strict 'refs'" temporarily so you can play around with the symbol table. For example:

    @colors = qw(red blue green yellow orange purple violet);
    for my $name (@colors) {
        no strict 'refs';  # renege for the block
        *$name = sub { "<FONT COLOR='$name'>@_</FONT>" };
    }

All those functions (red(), blue(), green(), etc.) appear to be separate, but the real code in the closure actually was compiled only once.

So, sometimes you might want to use symbolic references to directly manipulate the symbol table. This doesn't matter for formats, handles, and subroutines, because they are always global--you can't use my() on them. For scalars, arrays, and hashes, though--and usually for subroutines-- you probably only want to use hard references.

What does "bad interpreter" mean?

The "bad interpreter" message comes from the shell, not perl. The actual message may vary depending on your platform, shell, and locale settings.

If you see "bad interpreter - no such file or directory", the first line in your perl script (the "shebang" line) does not contain the right path to perl (or any other program capable of running scripts). Sometimes this happens when you move the script from one machine to another and each machine has a different path to perl---/usr/bin/perl versus /usr/local/bin/perl for instance.

If you see "bad interpreter: Permission denied", you need to make your script executable.

In either case, you should still be able to run the scripts with perl explicitly:

        % perl script.pl

If you get a message like "perl: command not found", perl is not in your PATH, which might also mean that the location of perl is not where you expect it so you need to adjust your shebang line.

AUTHOR AND COPYRIGHT

Copyright (c) 1997-2002 Tom Christiansen and Nathan Torkington. All rights reserved.

This documentation is free; you can redistribute it and/or modify it under the same terms as Perl itself.

Irrespective of its distribution, all code examples in this file are hereby placed into the public domain. You are permitted and encouraged to use this code in your own programs for fun or for profit as you see fit. A simple comment in the code giving credit would be courteous but is not required.

譯者

陳彥銘,蕭百齡,兩隻老虎工作室

本頁面中文版由中文 man 手冊頁計劃提供。
中文 man 手冊頁計劃:https://github.com/man-pages-zh/manpages-zh

2003-11-25 perl v5.8.3