perltrap - Perl 不留意者的陷阱
最大的陷阱是忘記使用 use warnings
或使用 -w 選項;請參閱 warnings 和 perlrun 中的 "-w"。第二大的陷阱是沒有讓整個程式在 use strict
下可執行。第三大的陷阱是沒有閱讀這個版本的 Perl 中的變更清單;請參閱 perldelta。
習慣使用 awk 的用戶應特別注意以下事項
Perl 程式只執行一次,而不是每個輸入行都執行一次。您可以使用 -n
或 -p
進行隱式循環。
通過載入的 English 模塊
use English;
讓您可以像在 awk 中一樣使用名稱(如 $RS)來引用特殊變量(如 $/
);詳情請參閱 perlvar。
在 Perl 中,所有簡單語句後都需要分號(除了在塊的末尾)。換行符不是語句分隔符。
在 Perl 中,if
和 while
语句中需要使用大括号。
在 Perl 中,变量以 "$"、"@" 或 "%" 开头。
数组的索引从 0 开始。同样,在 substr() 和 index() 中字符串的位置也是从 0 开始。
您必须决定您的数组是具有数字索引还是字符串索引。
哈希值不会在引用时自动生成。
您必须决定是否要使用字符串比较还是数字比较。
读取输入行不会自动分割。您需要自行将其分割为数组。而且 split() 操作符的参数与 awk 不同。
当前的输入行通常存储在 $_ 中,而不是 $0。通常不会去除换行符。($0 是正在执行的程序的名称。)请参阅 perlvar。
$<数字> 不是引用字段,而是引用上一次匹配的子字符串。
print() 语句不会添加字段和记录分隔符,除非您设置了 $,
和 $\
。如果您使用英语模块,您可以设置 $OFS 和 $ORS。
在打印之前,您必须先打开文件。
范围运算符是 "..",而不是逗号。逗号操作符的用法与 C 语言相同。
匹配运算符是 "=~",而不是 "~"。("~" 是按位取反运算符,与 C 语言相同。)
指数运算符是 "**",而不是 "^"。"^" 是按位异或运算符,与 C 语言相同。 (您知道,人们可能会觉得 awk 基本上与 C 语言不兼容。)
连接运算符是 ".",而不是空字符串。 (使用空字符串会导致 /pat/ /pat/
解析错误,因为第三个斜杠会被解释为除法运算符--分词器实际上在某种程度上对类似 "/", "?", 和 ">" 的操作符稍微具有上下文敏感性。实际上,"." 本身也可以是数字的开头。)
next
、exit
和 continue
关键字的工作方式不同。
以下变量的工作方式不同
Awk Perl
ARGC scalar @ARGV (compare with $#ARGV)
ARGV[0] $0
FILENAME $ARGV
FNR $. - something
FS (whatever you like)
NF $#Fld, or some such
NR $.
OFMT $#
OFS $,
ORS $\
RLENGTH length($&)
RS $/
RSTART length($`)
SUBSEP $;
您不能将 $RS 设置为模式,只能设置为字符串。
如果有疑问,请将 awk 结构运行通过 a2p,看看它给您的结果。
聰明的 C 和 C++ 程式設計師應該注意以下事項
在 if
和 while
中需要使用大括號。
必須使用 elsif
而不是 else if
。
來自 C 的 break
和 continue
關鍵字在 Perl 中分別成為 last
和 next
。與 C 不同,這些關鍵字在 do { } while
構造中無效。請參閱 perlsyn 中的 "Loop Control"。
switch 陳述句在 Perl 中稱為 given
/when
,只在 perl 5.10 或更新版本中可用。請參閱 perlsyn 中的 "Switch Statements"。
在 Perl 中,变量以 "$"、"@" 或 "%" 开头。
註釋以 "#" 開始,而不是 "/*" 或 "//"。Perl 可能將 C/C++ 註釋解釋為除法運算符、未結束的正則表達式或定義的或運算符。
你無法取得任何東西的地址,但在 Perl 中類似的運算符是反斜線,它創建一個參考。
ARGV
必須大寫。 $ARGV[0]
對應於 C 的 argv[1]
,而 argv[0]
最終會成為 $0
。
系統調用,如 link()、unlink()、rename() 等,在成功時返回非零值,而不是 0。(然而,system() 在成功時返回零。)
信號處理程序處理信號名稱,而不是數字。使用 kill -l
在您的系統上查找它們的名稱。
明智的 JavaScript 程式設計師應該注意以下事項
在 Perl 中,二進制 +
總是加法。 $string1 + $string2
將兩個字符串都轉換為數字,然後將它們相加。要連接兩個字符串,請使用 .
運算符。
在 Perl 中,一元運算符 +
不起作用。它存在是為了避免語法上的歧義。
與 for...in
不同,Perl 的 for
(也可以拼寫為 foreach
)不允許左側是任意表達式。它必須是一個變量
for my $variable (keys %hash) {
...
}
此外,不要忘記其中的 keys
,因為 foreach my $kv (%hash) {}
遍歷鍵和值,通常並不有用($kv 將是一個鍵,然後是一個值,依此類推)。
要遍歷數組的索引,使用 foreach my $i (0 .. $#array) {}
。 foreach my $v (@array) {}
遍歷值。
Perl 要求在 if
、while
、foreach
等後面使用大括號。
在 Perl 中,else if
的拼寫是 elsif
。
? :
的優先順序高於賦值。在 JavaScript 中,可以這樣寫
condition ? do_something() : variable = 3
如果條件為假,變數才會被賦值。在Perl中,您需要使用括號。
$condition ? do_something() : ($variable = 3);
或者只需使用if
。
Perl需要分號來分隔語句。
使用my
聲明的變量只會影響聲明之後的代碼。您不能寫$x = 1; my $x;
並期望第一個賦值會影響同一變量。它會賦值給之前在外部作用域聲明的$x
,或者全局變量。
還要注意變量直到下一個語句才可見。這意味著在my $x = 1 + $x
中,第二個$x是指之前聲明的一個。
my
變量的作用域僅限於當前區塊,而不是當前函數。如果您寫{my $x;} $x;
,第二個$x
不會指向在塊內聲明的那個。
對象的成員無法作為變量訪問。最接近Perl等效於with(object) { method() }
的是for
,它可以將$_
別名為該對象。
for ($object) {
$_->method;
}
方法調用所在的對象或類別作為方法的一個參數傳遞,而不是作為單獨的this
值。
經驗豐富的sed程序員應該注意以下事項
Perl 程式只執行一次,而不是每個輸入行都執行一次。您可以使用 -n
或 -p
進行隱式循環。
替換中的反向引用使用"$"而不是"\\"。
模式匹配的元字符"(",")"和"|"前面沒有反斜線。
範圍運算符是...
而不是逗號。
精通shell的程序員應該注意以下事項
反引號運算符在不考慮命令中單引號存在的情況下進行變量插值。
反引號運算符不會對返回值進行任何轉換,不像csh。
shell(尤其是csh)對每個命令行進行多級替換。Perl僅對某些結構進行替換,如雙引號,反引號,角括號和搜索模式。
shell會逐個解釋腳本。Perl在執行之前編譯整個程序(除了BEGIN
塊,在編譯時執行)。
參數通過@ARGV可用,而不是$1,$2等。
環境不會自動提供為單獨的純量變數。
Shell 的 test
用於字串比較的運算符是 "=", "!=", "<" 等,用於數值比較的運算符是 "-eq"、"-ne"、"-lt" 等。這與 Perl 相反,Perl 使用 eq
、ne
、lt
進行字串比較,而使用 ==
、!=
、<
等進行數值比較。
Perl 程式設計師應該注意以下事項
請記住,許多操作在列表上下文中的行為與在純量上下文中的行為不同。詳細請參閱 perldata。
如果可以的話,請避免使用裸字,尤其是全部小寫的字。僅僅通過外觀無法判斷裸字是函數還是字串。通過對字串使用引號和對函數調用使用括號,您就不會將它們弄混。
您無法僅通過檢查來區分哪些內置函數是一元運算符(如 chop() 和 chdir())以及哪些是列表運算符(如 print() 和 unlink())。 (除非有原型,否則用戶定義的子例程只能是列表運算符,而不是一元運算符。)詳細請參閱 perlop 和 perlsub。
人們很難記住某些函數默認是基於 $_、@ARGV 或其他變數的,但是其他一些您可能期望的函數卻不是。
<FH> 構造不是文件句柄的名稱,而是對該句柄的讀取操作。只有在 while 循環中文件讀取是唯一的條件時,讀取的數據才會被賦值給 $_。
while (<FH>) { }
while (defined($_ = <FH>)) { }..
<FH>; # data discarded!
請記住,當您需要 =~
時,不要使用 =
;這兩個構造是完全不同的。
$x = /foo/;
$x =~ /foo/;
do {}
構造不是一個您可以在其上使用循環控制的真正循環。
盡可能在本地變量中使用 my()
(但請參閱 perlform,了解不能這樣做的情況)。使用 local()
實際上是為全局變量提供了局部值,這會使您暴露於動態作用域的未預見的副作用。
如果您在模塊中將一個已導出的變量局部化,則其導出值將不會更改。本地名稱變成了對新值的別名,但是外部名稱仍然是對原始值的別名。
總之,如果這些任何一個被正式宣佈為錯誤,它們將被修正並移除。