2012-07-26 21 views
5

Tôi đang sử dụng reval từ mô-đun Safe của Perl và tôi muốn ngăn chặn cảnh báo này nếu chuỗi không được phân tích cú pháp (thực ra, tôi muốn ngăn chặn nó tạo ra bất kỳ cảnh báo nào) ."không cảnh báo;" trong một khoang an toàn

Ví dụ, đoạn mã sau:

use strict; use warnings; 
use Safe;  
use feature qw/say/; 
my $cft = Safe->new; 

my $x = $cft->reval(') 1'); 
my $y = $cft->reval('2' ); 
say "x: $x"; 
say "y: $y"; 

kết quả trong:

Number found where operator expected at (eval 5) line 1, near ") 1" 
    (Missing operator before 1?) 
Use of uninitialized value $x in concatenation (.) or string at ./test line 12. 
x: 
y: 2 

Những gì tôi đang cố gắng để đạt được là phải có $ x = undef và $ y = 2, và không có cảnh báo. Tôi đã cố gắng đặt "không có cảnh báo"; bên trong một phạm vi mới, nhưng nó không ảnh hưởng đến những lời cảnh báo được sản xuất từ ​​bên trong Reval (mặc dù, như đã chỉ ra bởi @DavidO, nó im lặng của các giá trị chưa được khởi tạo 'cảnh báo):

use strict; use warnings; 
use Safe;  
use feature qw/say/; 
my $cft = Safe->new; 
{ 
    no warnings; 
    my $x = $cft->reval(') 1'); 
    my $y = $cft->reval('2' ); 
    say "x: $x"; 
    say "y: $y"; 
} 

Tôi đoán rằng bằng cách nào đó 'không có cảnh báo' phải ở trong ngăn An toàn, vì vậy tôi cũng đã cố gắng thêm "không có cảnh báo"; để các dây được eval'ed:

use strict; use warnings; 
use Safe; 
use feature qw/say/; 
my $cft = Safe->new; 
{ 
    my $x = $cft->reval('no warnings;' . ') 1'); 
    my $y = $cft->reval('no warnings;' . '2' ); 
    say "x: $x"; 
    say "y: $y"; 
} 

cách Reval này không phát hành bất kỳ cảnh báo, nhưng cả hai biến là undef:

Use of uninitialized value $x in concatenation (.) or string at ./test line 10. 
x: 
Use of uninitialized value $y in concatenation (.) or string at ./test line 11. 
y: 

Tôi không biết những gì khác để thử, và tôi hy vọng mô tả sự cố đủ rõ ràng.

+1

Lần thử thứ hai của bạn thực sự không tạo ra cùng một đầu ra như lần đầu tiên. Nó vẫn tạo ra lỗi "compiletime" (thực sự là lỗi compiletime reval), nhưng không phải là cảnh báo thời gian chạy liên quan đến nội suy một giá trị uninitialized trong câu lệnh 'say' của bạn. Vì vậy, bạn đã thực sự giải quyết được một nửa vấn đề của mình (lập lại cảnh báo) trong đoạn mã thứ hai ở trên. Nửa còn lại (làm sai lệch thời gian biên dịch) có vấn đề hơn. – DavidO

+0

Vâng, bạn đúng về điều đó. Tôi thậm chí không nhận thấy rằng bởi vì mối quan tâm chính của tôi ở đây thực sự là vòng quay - cảnh báo biến không được khởi tạo là kết quả của việc tôi cố gắng giữ ví dụ ngắn gọn. Dù sao, tôi đã cập nhật các bài viết để làm cho nó rõ ràng hơn. Cảm ơn! – andrefs

Trả lời

4

Nếu bạn kiểm tra [email protected] bạn sẽ thấy rằng $cft->reval('no warnings;' . ') 1'); không thành công. 'require' trapped by operation mask at (eval 5) line 1.. Nói cách khác, Safe đang thực hiện công việc của mình và ngăn chặn mã đó cố tải một thư viện.

$cft->reval('BEGIN { warnings->unimport; }) 1'); sẽ hoạt động, giả sử cảnh báo đã được tải bên ngoài khoang. Tuy nhiên, điều đó sẽ không gây ra lỗi thời gian biên dịch. Không giống như eval, reval dường như cho phép họ vượt qua. Sử dụng kỹ thuật làm im lặng STDERR của amon.

+0

Cách tiếp cận hai tầng hoạt động tốt nhất. Cảnh báo đang được tạo ra bên ngoài 'reval', và có thể được vẽ ở phạm vi rộng hơn. Lỗi compiletime được tạo ra bên trong 'reval', và khá cứng đầu. Đây là nơi chuyển hướng STDERR là tùy chọn ít xấu nhất, imho. (Tùy chọn khác để cho phép rõ ràng 'eval' bên trong khoang an toàn, nhưng tại sao lại bận tâm sử dụng Save? :)). – DavidO

+0

Thật buồn cười; thực hiện một ''qr/[c-a] /'' bên trong ngăn an toàn, đó là một regex không hợp lệ sẽ ném một lỗi khi nó đang được biên dịch, bị bẫy thành công bởi reval. – DavidO

+0

Cảm ơn bạn đã trả lời. Phương pháp của @ amon có vẻ là giải pháp thay thế tốt nhất cho sự im lặng ngay cả những lỗi phân tích cú pháp nghiêm trọng nhất. BEGIN {warnings-> unimport;} dường như hoạt động ngoại trừ nếu bạn gọi một cách rõ ràng một cái gì đó như cảnh báo "foo" trong chuỗi đang được đánh giá: P – andrefs

4

no warnings ngăn chặn tất cả các cảnh báo mà use warnings tạo ra pragma. Bạn có thể muốn loại bỏ bất kỳ strict ures là tốt. Nhưng lỗi phân tích cú pháp nghiêm trọng sẽ bật lên theo bất kỳ cách nào.

Nếu bạn muốn thực hiện bất kỳ mã nào, dù bệnh lý, mà không cần bất kỳ đầu ra stderr, bạn ở địa phương nên sửa đổi xử lý tín hiệu:

{ 
    # I know what I'm doing! 
    local $SIG{__WARN__} = sub {}; # locally ignore any warnings 
    eval $code; # catches all "die" 
} 

hoặc chúng ta có thể mở lại STDERR-/dev/null:

{ 
    # I know what I'm doing! 
    open my $oldSTDERR, '>&' \*STDERR or die; 
    close STDERR or die; 
    open STDERR, '>', '/dev/null' or die; 

    eval $code; 

    close STDERR or die; 
    open STDERR, '>&', $oldSTDERR or die; 
    close $oldSTDERR; 
} 
+1

Nhưng 'eval $ code' không được phép trong một khoang an toàn. Tôi nghĩ rằng việc thiết lập các trình xử lý '$ SIG {}' cũng bị cấm (và vì lý do chính đáng).Việc thiết lập một trình xử lý '$ SIG {}' bên ngoài 'reval' sẽ không hiệu quả. Tôi nghĩ rằng chuyển hướng STDERR có lẽ là kludge sạch nhất đối với các lỗi được tạo ra trong khi biên dịch mã reval. Các cảnh báo có thể được squelched thông qua các phương tiện bình thường, kể từ khi nó xảy ra bên ngoài của reval. – DavidO

+0

Giải pháp đầu tiên được đề xuất bởi @amon đang làm việc trong mã sau: sử dụng nghiêm ngặt; sử dụng cảnh báo; sử dụng An toàn; tính năng sử dụng qw/say /; my $ cft = Safe-> new; { địa phương $ SIG {__ WARN__} = sub {}; my $ x = $ cft-> reval (') 1'); my $ y = $ cft-> reval ('2'); nói "x: $ x"; nói "y: $ y"; } Điều này dường như chính xác những gì tôi đang tìm kiếm, cảm ơn! – andrefs

+0

@andrefs Nếu câu trả lời này phù hợp với bạn, vui lòng "chấp nhận" câu trả lời này để đánh dấu câu hỏi của bạn là "đã đóng". – amon

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