Perl - 錯誤處理



執行和錯誤總是同時存在。如果你開啟一個不存在的檔案,那麼如果你沒有正確處理這種情況,你的程式就被認為是低質量的。

如果發生錯誤,程式將停止執行。因此,適當的錯誤處理用於處理程式執行過程中可能發生的各種型別的錯誤,並採取相應的措施,而不是完全停止程式。

你可以透過多種不同的方式識別和捕獲錯誤。在 Perl 中捕獲錯誤然後正確處理它們非常容易。這裡有一些可以使用的的方法。

if 語句

當你需要檢查語句的返回值時,if 語句是顯而易見的選擇;例如:

if(open(DATA, $file)) {
   ...
} else {
   die "Error: Couldn't open the file - $!";
}

這裡變數 $! 返回實際的錯誤訊息。或者,在有意義的情況下,我們可以將語句簡化為一行;例如:

open(DATA, $file) || die "Error: Couldn't open the file $!";

unless 函式

unless 函式與 if 的邏輯相反:語句可以完全繞過成功狀態,只有在表示式返回 false 時才執行。例如:

unless(chdir("/etc")) {
   die "Error: Can't change directory - $!";
}

當你想只在表示式失敗時引發錯誤或替代方案時,unless 語句最好用。當用於單行語句時,該語句也有意義:

die "Error: Can't change directory!: $!" unless(chdir("/etc"));

只有在 chdir 操作失敗時我們才會 die,而且讀起來很流暢。

三元運算子

對於非常短的測試,可以使用條件運算子 ?:

print(exists($hash{value}) ? 'There' : 'Missing',"\n");

這裡不太清楚我們試圖實現什麼,但效果與使用 ifunless 語句相同。當你想在一個表示式或語句中快速返回兩個值中的一個時,條件運算子最好用。

warn 函式

warn 函式只發出警告,一條訊息將列印到 STDERR,但不會採取進一步的措施。因此,如果你只想為使用者列印警告並繼續執行其餘操作,它更有用:

chdir('/etc') or warn "Can't change directory";

die 函式

die 函式的工作方式與 warn 類似,只是它還會呼叫 exit。在一個普通的指令碼中,這個函式的效果是立即終止執行。如果程式中出現錯誤,繼續執行是沒有意義的,你應該使用此函式:

chdir('/etc') or die "Can't change directory";

模組中的錯誤

我們應該能夠處理兩種不同的情況:

  • 報告模組中的錯誤,該錯誤引用模組的檔名和行號——這在除錯模組時很有用,或者當你想引發與模組相關的而不是與指令碼相關的錯誤時。

  • 報告模組中的錯誤,該錯誤引用呼叫者的資訊,以便你可以除錯導致錯誤的指令碼中的行。以這種方式引發的錯誤對終端使用者很有用,因為它們突出了與呼叫指令碼的原始行相關的錯誤。

當從模組中呼叫時,warndie 函式的工作方式與你預期略有不同。例如,簡單的模組:

package T;

require Exporter;
@ISA = qw/Exporter/;
@EXPORT = qw/function/;
use Carp;

sub function {
   warn "Error in module!";
}
1;

當從如下指令碼呼叫時:

use T;
function();

它將產生以下結果:

Error in module! at T.pm line 9.

這或多或少是你可能預期的,但不一定是你想看到的。從模組程式設計師的角度來看,這些資訊很有用,因為它有助於指出模組本身中的錯誤。對於終端使用者來說,提供的資訊相當無用,對於除經驗豐富的程式設計師以外的所有人來說,它完全沒有意義。

解決此類問題的方案是 Carp 模組,它提供了一種簡化的方法來報告模組中的錯誤,這些錯誤返回有關呼叫指令碼的資訊。Carp 模組提供四個函式:carp、cluck、croak 和 confess。這些函式將在下面討論。

carp 函式

carp 函式是 warn 的基本等價物,它將訊息列印到 STDERR,而不會實際退出指令碼並列印指令碼名稱。

package T;

require Exporter;
@ISA = qw/Exporter/;
@EXPORT = qw/function/;
use Carp;

sub function {
   carp "Error in module!";
}
1;

當從如下指令碼呼叫時:

use T;
function();

它將產生以下結果:

Error in module! at test.pl line 4

cluck 函式

cluck 函式是一種增強的 carp,它遵循相同的基本原理,但還會列印導致呼叫該函式的所有模組的堆疊跟蹤,包括原始指令碼的資訊。

package T;

require Exporter;
@ISA = qw/Exporter/;
@EXPORT = qw/function/;
use Carp qw(cluck);

sub function {
   cluck "Error in module!";
}
1;

當從如下指令碼呼叫時:

use T;
function();

它將產生以下結果:

Error in module! at T.pm line 9
   T::function() called at test.pl line 4

croak 函式

croak 函式等同於 die,只是它向上報告一個級別的呼叫者。與 die 一樣,此函式還會在將錯誤報告到 STDERR 後退出指令碼:

package T;

require Exporter;
@ISA = qw/Exporter/;
@EXPORT = qw/function/;
use Carp;

sub function {
   croak "Error in module!";
}
1;

當從如下指令碼呼叫時:

use T;
function();

它將產生以下結果:

Error in module! at test.pl line 4

與 carp 一樣,關於根據 warn 和 die 函式包含行和檔案資訊的相同基本規則適用。

confess 函式

confess 函式類似於 cluck;它呼叫 die,然後列印一直到原始指令碼的堆疊跟蹤。

package T;

require Exporter;
@ISA = qw/Exporter/;
@EXPORT = qw/function/;
use Carp;

sub function {
   confess "Error in module!";
}
1;

當從如下指令碼呼叫時:

use T;
function();

它將產生以下結果:

Error in module! at T.pm line 9
   T::function() called at test.pl line 4
廣告
© . All rights reserved.