2016-10-06 47 views
5

xem xét chương trình này nhỏ perl, test.pl:Trình gỡ rối Perl - ngắt lỗi (ngoại lệ)?

#!/usr/bin/env perl 
use warnings; 
use strict; 
use Number::Format qw(:subs); # sudo perl -MCPAN -e 'install Number::Format' 

my $tstr = ""; 
my $numFormatter = new Number::Format(); 

for (my $ix=0; $ix<20; $ix++) { 
    $tstr = $tstr . int(rand(10)); 
    my $ftstr = $numFormatter->format_number($tstr, 2, 1); 
    print "ix: $ix ; in: $tstr ; out: $ftstr\n"; 
} 

Nếu tôi chạy nó, nó không thành công với một lỗi. Nếu tôi chạy nó trong trình gỡ lỗi Perl, sử dụng perl -d, nó cũng không thành công với một lỗi:

$ perl -d test.pl 

Loading DB routines from perl5db.pl version 1.39_10 
Editor support available. 

Enter h or 'h h' for help, or 'man perldebug' for more help. 

main::(test.pl:6): my $tstr = ""; 
    DB<1> c 
ix: 0 ; in: 6 ; out: 6.00 
ix: 1 ; in: 63 ; out: 63.00 
ix: 2 ; in: 637 ; out: 637.00 
ix: 3 ; in: 6379 ; out: 6,379.00 
ix: 4 ; in: 63790 ; out: 63,790.00 
ix: 5 ; in: 637906 ; out: 637,906.00 
ix: 6 ; in: 6379062 ; out: 6,379,062.00 
ix: 7 ; in: 63790624 ; out: 63,790,624.00 
ix: 8 ; in: 637906246 ; out: 637,906,246.00 
ix: 9 ; in: 6379062467 ; out: 6,379,062,467.00 
ix: 10 ; in: 63790624671 ; out: 63,790,624,671.00 
ix: 11 ; in: 637906246715 ; out: 637,906,246,715.00 
ix: 12 ; in: 6379062467152 ; out: 6,379,062,467,152.00 
ix: 13 ; in: 63790624671522 ; out: 63,790,624,671,522.00 
round() overflow. Try smaller precision or use Math::BigFloat at test.pl line 11. 
at /usr/local/share/perl/5.18.2/Number/Format.pm line 535. 
    Number::Format::round('Number::Format=HASH(0x9d0b6cc)', 637906246715226, 2) called at /usr/local/share/perl/5.18.2/Number/Format.pm line 601 
    Number::Format::format_number('Number::Format=HASH(0x9d0b6cc)', 637906246715226, 2, 1) called at test.pl line 11 
Debugged program terminated. Use q to quit or R to restart, 
use o inhibit_exit to avoid stopping after program termination, 
h q, h R or h o to get additional info. 
    DB<1> p $ix   

    DB<2> 

... nhưng khi nó không thành công, nó không "dừng" ở dòng thất bại, như nói với gdb một chương trình C có thể làm - chương trình lại kết thúc, và do đó tôi không có biến ngữ cảnh nào để kiểm tra nữa.

Tất nhiên, một vòng như thế này có thể chạy cho hàng ngàn lần, đó là lý do tại sao thiết lập một breakpoint tại dòng có vấn đề và làm một c ontinue bằng tay sẽ không giúp được gì nhiều ở đây ...

Có cách nào để có trình gỡ lỗi Perl phá vỡ một chương trình khi lỗi/ngoại lệ, sao cho bối cảnh biến cục bộ được giữ nguyên, để kiểm tra các biến đó?

Trả lời

5

Bọc dòng vi phạm trong một eval và thiết lập $DB::single khi [email protected] được thiết lập:

#!/usr/bin/env perl 
use warnings; 
use strict; 
use Number::Format qw(:subs); # sudo perl -MCPAN -e 'install Number::Format' 

my $tstr = ""; 
my $numFormatter = new Number::Format(); 

for (my $ix=0; $ix<20; $ix++) { 
    $tstr = $tstr . int(rand(10)); 
    my $ftstr = eval { $numFormatter->format_number($tstr, 2, 1); }; 
    $DB::single = 1 if [email protected]; 
    print "ix: $ix ; in: $tstr ; out: $ftstr\n"; 
} 

Sau đó,

% perl -d test.pl 

Loading DB routines from perl5db.pl version 1.49 
Editor support available. 

Enter h or 'h h' for help, or 'man perldebug' for more help. 

main::(test.pl:6): my $tstr = ""; 

    DB<1> r 
ix: 0 ; in: 7 ; out: 7.00 
ix: 1 ; in: 71 ; out: 71.00 
ix: 2 ; in: 715 ; out: 715.00 
ix: 3 ; in: 7153 ; out: 7,153.00 
ix: 4 ; in: 71537 ; out: 71,537.00 
ix: 5 ; in: 715379 ; out: 715,379.00 
ix: 6 ; in: 7153794 ; out: 7,153,794.00 
ix: 7 ; in: 71537941 ; out: 71,537,941.00 
ix: 8 ; in: 715379417 ; out: 715,379,417.00 
ix: 9 ; in: 7153794174 ; out: 7,153,794,174.00 
ix: 10 ; in: 71537941740 ; out: 71,537,941,740.00 
ix: 11 ; in: 715379417408 ; out: 715,379,417,408.00 
ix: 12 ; in: 7153794174086 ; out: 7,153,794,174,086.00 
ix: 13 ; in: 71537941740864 ; out: 71,537,941,740,864.00 
main::(test.pl:13): print "ix: $ix ; in: $tstr ; out: $tstr\n"; 

    DB<1> print $tstr 
715379417408646 

    DB<2> 

gì Heck ??

Đằng sau sự kỳ diệu là hai nguyên tắc:

  1. Ngăn ngừa trường hợp ngoại lệ không bị tử vong (ví dụ bắt ngoại lệ)
  2. Dừng các chương trình gỡ rối tại một điểm nhất định trong mã mà không bước lặp đi lặp lại

Để bắt ngoại lệ, hãy sử dụng cấu trúc eval BLOCK. Điều này sẽ lưu ngoại lệ trong biến số [email protected]. Nếu [email protected] không phải là chuỗi rỗng, một ngoại lệ đã được ném. Lưu ý rằng đoạn mã trên, trong khi thành ngữ, không hoàn toàn chính xác; nếu trường hợp ngoại lệ được ném là chuỗi 0, nó sẽ bị bỏ qua (vì if 0 sẽ là sai). Xử lý ngoại lệ trong Perl là phức tạp. Try::Tiny có một cuộc thảo luận tốt.

Bây giờ ngoại lệ không còn gây tử vong nữa, làm thế nào để dừng trình gỡ lỗi? Có một số cách để làm điều đó. Ví dụ này sử dụng biến số $DB::single, khi đúng, báo hiệu trình gỡ rối dừng lại. Nhược điểm là bạn phải chỉnh sửa mã của bạn để thực hiện hành vi này. Một lựa chọn khác là để set a breakpoint with a condition:

% perl -d test.pl 

Loading DB routines from perl5db.pl version 1.49 
Editor support available. 

Enter h or 'h h' for help, or 'man perldebug' for more help. 

main::(test.pl:6): my $tstr = ""; 

    DB<1> b 11 [email protected] ne '' 
    DB<2> r 
[... output as above ...] 
main::(test.pl:11): my $ftstr = eval { $numFormatter->format_number($tstr, 2, 1); }; 

    DB<2> p $tstr 
3247014520717436 

Xem perl debugger documentation để biết thêm.

+0

Đó là tốt, nhưng nó chỉ gỡ lỗi rất cụ thể. Bạn có thể muốn mở rộng trên '$ DB :: single'. – simbabque

+0

Tuyệt vời - cảm ơn vì điều đó, @DiabJerius – sdbbs

+0

@simbabque Tôi hiểu ý của bạn. Nhưng bên quan tâm sẽ nói "cái quái gì thế này là 'eval' và dòng nhiễu đó' $ @ ', và' $ DB :: single' ?? " và sẽ tìm kiếm và tìm hiểu nhiều hơn tôi có thể làm ở đây. Và bên không quan tâm sẽ vận chuyển hàng hóa, nó sẽ xảy ra bất kể. Một số liên kết đến tài liệu phù hợp và tôi sẽ thêm chúng. –

5

Bắt chết với eval{}$DB::single = 1 if [email protected]; là một mẹo hay, nhưng nếu bạn muốn truy cập nguồn gốc của sự cố trong thư viện, bạn cần đặt điểm ngắt tại vị trí phát sinh lỗi.

đây thực hiện với

DB<1> b Carp::croak 
    DB<2> c 
Carp::croak(/opt/local/lib/perl5/5.22/Carp.pm:166): 
166: sub croak { die shortmess @_ } 
    DB<3> T 
@ = DB::DB called from file '/opt/local/lib/perl5/5.22/Carp.pm' line 166 
. = Carp::croak('round() overflow. Try smaller precision or use Math::BigFloat') 
    called from file '/opt/local/lib/perl5/site_perl/5.22/Number/Format.pm' line 535 
$ = Number::Format::round(ref(Number::Format), 637906246715227, 2) 
    called from file '/opt/local/lib/perl5/site_perl/5.22/Number/Format.pm' line 601 
$ = Number::Format::format_number(ref(Number::Format), 637906246715227, 2, 1) 
    called from file 'mytest.pl' line 12 
+0

Giải pháp thanh lịch. –

Các vấn đề liên quan