內容

名稱

constant - Perl pragma 用於宣告常數

語法

use constant PI    => 4 * atan2(1, 1);
use constant DEBUG => 0;

print "Pi equals ", PI, "...\n" if DEBUG;

use constant {
    SEC   => 0,
    MIN   => 1,
    HOUR  => 2,
    MDAY  => 3,
    MON   => 4,
    YEAR  => 5,
    WDAY  => 6,
    YDAY  => 7,
    ISDST => 8,
};

use constant WEEKDAYS => qw(
    Sunday Monday Tuesday Wednesday Thursday Friday Saturday
);

print "Today is ", (WEEKDAYS)[ (localtime)[WDAY] ], ".\n";

說明

此 pragma 允許您在編譯時宣告常數。

當您使用上述方法宣告常數(例如 PI)時,執行腳本的每部電腦都能使用其所能使用的最大精確度位數。此外,您的程式會更容易閱讀、更容易維護(並正確維護),而且不太可能因為沒有人注意到您在其中一個等式中寫入 3.14195 而將太空探測器送往錯誤的星球。

當常數用於表達式時,Perl 會在編譯時將其替換為其值,然後可能進一步最佳化表達式。特別是,如果常數為 false,則 if (CONSTANT) 程式區塊中的任何程式碼都將被最佳化移除。

注意事項

與所有 use 指令一樣,定義常數會在編譯時期發生。因此,將常數宣告放入條件式陳述中(例如 if ($foo) { use constant ... })可能不正確。

使用此模組定義的常數無法像變數一樣插入字串中。不過,串接運作正常

print "Pi equals PI...\n";        # WRONG: does not expand "PI"
print "Pi equals ".PI."...\n";    # right

即使參考可能宣告為常數,參考仍可能指向可以變更的資料,如下列程式碼所示。

use constant ARRAY => [ 1,2,3,4 ];
print ARRAY->[1];
ARRAY->[1] = " be changed";
print ARRAY->[1];

常數屬於定義它們的套件。若要參考在其他套件中定義的常數,請指定完整的套件名稱,例如 Some::Package::CONSTANT。常數可以由模組匯出,也可以作為類別或執行個體方法呼叫,亦即,作為 Some::Package->CONSTANT 或作為 $obj->CONSTANT,其中 $objSome::Package 的執行個體。子類別可以定義自己的常數來覆寫其基底類別中的常數。

從此模組的 1.32 版開始,常數可以定義在呼叫者以外的套件中,方法是在常數名稱中包含套件名稱

use constant "OtherPackage::FWIBBLE" => 7865;
constant->import("Other::FWOBBLE",$value); # dynamically at run time

使用全大寫作為常數名稱只是一個慣例,不過建議這樣做,以使常數顯著,並有助於避免與其他裸字、關鍵字和子常式名稱發生衝突。常數名稱必須以字母或底線開頭。以雙底線開頭的名稱是保留的。如果在編譯時期啟用警告,一些不佳的名稱選擇會產生警告。

列出常數

常數可以是多個(或少於一個)值的清單。沒有值的常數在純量內容中會評估為 undef。請注意,具有多個值的常數並不會在純量內容中傳回它們的最後一個值,就像人們預期的那樣。它們目前傳回值的數量,但這可能會在未來改變。請勿在純量內容中使用具有多個值的常數。

注意:這表示定義常數值的表達式是在清單內容中評估的。這可能會產生驚喜

use constant TIMESTAMP => localtime;                # WRONG!
use constant TIMESTAMP => scalar localtime;         # right

上面的第一行將 TIMESTAMP 定義為 9 個元素的清單,就像 localtime() 在清單內容中傳回的。若要將其設定為 localtime() 在標量內容中傳回的字串,則需要明確的 scalar 關鍵字。

清單常數是清單,不是陣列。若要索引或切片它們,必須將它們放在括號中。

my @workdays = WEEKDAYS[1 .. 5];            # WRONG!
my @workdays = (WEEKDAYS)[1 .. 5];          # right

定義多個常數

您不必撰寫多個 use constant 陳述式,而是可以在單一陳述式中定義多個常數,方法是提供一個雜湊的參考,其中金鑰是所定義常數的名稱,而不是常數名稱。顯然地,使用此方法定義的所有常數都必須具有單一值。

use constant {
    FOO => "A single value",
    BAR => "This", "won't", "work!",        # Error!
};

這是 Perl 中雜湊建構方式的基本限制。當發生這種情況時產生的錯誤訊息通常會相當難懂,最糟糕的情況是可能完全沒有,而您只能在稍後發現某些東西損壞了。

在定義多個常數時,您不能使用在同一個宣告中定義的其他常數的值。這是因為呼叫套件在 use 陳述式完成之後才知道該群組中的任何常數。

use constant {
    BITMASK => 0xAFBAEBA8,
    NEGMASK => ~BITMASK,                    # Error!
};

神奇常數

神奇值和參考可以在編譯時轉換為常數,允許執行像這樣很酷的事情。(這些錯誤號碼並非完全可移植,唉。)

use constant E2BIG => ($! = 7);
print   E2BIG, "\n";        # something like "Arg list too long"
print 0+E2BIG, "\n";        # "7"

您不能透過提供繫結標量作為值來產生繫結常數。然而,繫結變數的參考可以用作常數,而不會有任何問題。

技術說明

在目前的實作中,標量常數實際上是可內嵌的子常式。從 Perl 的 5.004 版開始,適當的標量常數會直接插入某些子常式呼叫的所在位置,從而節省子常式呼叫的開銷。有關如何以及何時發生這種情況的詳細資訊,請參閱 "perlsub 中的常數函式"

在極少數情況下,您需要在執行時找出是否已透過此模組宣告特定常數,您可以使用此函式來檢查雜湊 %constant::declared。如果給定的常數名稱不包含套件名稱,則使用目前的套件。

sub declared ($) {
    use constant 1.01;              # don't omit this!
    my $name = shift;
    $name =~ s/^::/main::/;
    my $pkg = caller;
    my $full_name = $name =~ /::/ ? $name : "${pkg}::$name";
    $constant::declared{$full_name};
}

注意事項

除非您使用 Perl v5.20 或更高版本,否則清單常數不會內嵌。在 v5.20 或更高版本中,它們仍然不是唯讀的,但這可能會在未來的版本中改變。

不可能在同一個套件中有一個子常式或關鍵字與常數同名。這可能是一件好事。

由於技術原因,名稱在清單 STDIN STDOUT STDERR ARGV ARGVOUT ENV INC SIG 中的常數只允許在套件 main:: 中使用。

與某些語言中的常數不同,這些常數不能在命令列或透過環境變數覆寫。

如果您在會自動引用裸字的內容中使用常數,您可能會遇到問題(對任何子常式呼叫都是如此)。例如,您不能說 $hash{CONSTANT},因為 CONSTANT 會被解釋為字串。使用 $hash{CONSTANT()}$hash{+CONSTANT} 來防止裸字引用機制啟動。類似地,由於 => 算子會引用其左邊的裸字,因此您必須說 CONSTANT() => 'value'(或僅在箭頭符號的位置使用逗號)而不是 CONSTANT => 'value'

另請參閱

Readonly - 建立唯讀標量、陣列、雜湊的工具。

Attribute::Constant - 透過屬性建立唯讀變數

Scalar::Readonly - Perl 擴充,用於 SvREADONLY 標量旗標

Hash::Util - 一系列通用雜湊子常式(主要用於鎖定/解鎖鍵和值)

錯誤

請透過 perlbug(1) 工具回報任何錯誤或功能要求。

作者

Tom Phoenix, <rootbeer@redcat.com>,並得到許多其他人的協助。

一次加入多個常數宣告由 Casey West, <casey@geeknest.com> 加入。

文件大部分由 Ilmari Karonen, <perl@itz.pp.sci.fi> 重新撰寫。

此程式由 Perl 5 Porters 維護。CPAN 發行版由 Sébastien Aperghis-Tramoni <sebastien@aperghis.net> 維護。

版權與授權

Copyright (C) 1997, 1999 Tom Phoenix

此模組為自由軟體;您可以在與 Perl 相同的條款下重新發布或修改它。