2012-06-29 31 views
14

So sánh sử dụng perl -w -Mstrict:Điều gì đang xảy ra khi() của tôi là có điều kiện?

# case Alpha 
print $c; 

...

# case Bravo 
if (0) { 
    my $c = 1; 
} 

print $c; 

...

# case Charlie 
my $c = 1 if 0; 
print $c; 

AlphaBravo cả phàn nàn về biểu tượng toàn cầu không có một tên gói rõ ràng, mà được mong đợi. Nhưng Charlie không đưa ra cảnh báo tương tự, duy nhất mà giá trị chưa được định hình, trong đó có mùi rất giống:

# case Delta 
my $c; 
print $c; 

Chính xác những gì đang xảy ra dưới mui xe? (Mặc dù một cái gì đó như thế này không bao giờ được viết cho mã sản xuất)

+1

Trong trường hợp Bravo, '$ c' được lexically scoped đến' nếu (0) ... 'khối, và nó là một lỗi (dưới 'sử dụng nghiêm ngặt') để tham chiếu đến nó bên ngoài khối đó. – mob

+5

Nhân tiện, hành vi của 'my $ c = 1 nếu 0; ... $ c ... 'là chính thức không xác định (và được ghi lại như vậy), có nghĩa là không được phép và có thể dẫn đến hành vi không mong muốn (ví dụ: bị lỗi). Vâng, nó sẽ không sụp đổ, nhưng nó có thể :) – ikegami

+1

@ikegami hmm bạn hoàn toàn đúng nó được liệt kê dưới phần "điều chỉnh tuyên bố" của perlsyn. lời nhắc nhở tốt! –

Trả lời

14

Bạn có thể nghĩ đến tuyên bố my là có hành động tại thời gian biên dịch và vào thời gian chạy. Tại thời điểm biên dịch, tuyên bố my yêu cầu trình biên dịch ghi chú rằng biểu tượng tồn tại và sẽ có sẵn cho đến khi kết thúc phạm vi từ vựng hiện tại. Việc chuyển nhượng hoặc sử dụng biểu tượng khác trong tuyên bố đó sẽ diễn ra vào thời gian chạy.

Vì vậy, ví dụ bạn

my $c = 1 if 0; 

là như

my $c;   # compile-time declaration, initialized to undef 
$c = 1 if 0; # runtime -- as written has no effect 

Lưu ý rằng sự khác biệt thời gian biên dịch/run-time này cho phép bạn viết mã như thế này.

my $DEBUG; # lexical scope variable declared at compile-time 
BEGIN { 
    $DEBUG = $ENV{MY_DEBUG}; # statement executed at compile-time 
}; 

Bây giờ bạn có thể đoán đầu ra của chương trình này là gì không?

my $c = 3; 
BEGIN { 
    print "\$c is $c\n"; 
    $c = 4; 
} 
print "\$c is $c\n"; 
+0

Câu trả lời tuyệt vời! Sự phân biệt thời gian biên dịch là chìa khóa bị thiếu. Cảm ơn nhiều! –

+4

'my' không có hiệu ứng thời gian chạy như bạn nói, nhưng bạn không đề cập đến nó là gì! [Nó đặt một chỉ thị trên ngăn xếp để xóa biến trên phạm vi thoát, sau đó nó trả về var là một lvalue.] Ok, nó có lẽ là tốt nhất mà bạn đã không đề cập đến điều đó. :) – ikegami

6

mob's answer là một lời giải thích tốt về những gì đang xảy ra (và tại sao), nhưng đừng quên rằng perldoc perlsyn cho chúng ta biết:

LƯU Ý: Hành vi của một my, state, hoặc our được sửa đổi bằng công cụ điều chỉnh câu lệnh hoặc cấu trúc vòng lặp (ví dụ: my $x if ...) là không xác định. Giá trị của biến số my có thể là undef, mọi giá trị được gán trước đây hoặc có thể là bất kỳ thứ gì khác. Đừng dựa vào nó. Phiên bản tương lai của perl có thể làm điều gì đó khác nhau từ phiên bản perl bạn dùng thử. Đây là rồng.

Không được tính vào kết quả đó hoặc giải thích cho nó vẫn đúng trong các phiên bản tương lai của Perl. (Mặc dù nó có lẽ sẽ.)

2

Các "của tôi $ foo = val nếu cond" xây dựng và xác định hành vi của nó đã cắn tôi nhiều lần trong những năm qua.Tôi muốn trình biên dịch có thể đơn giản từ chối nó (tại sao giữ một cái gì đó trong ngôn ngữ có hành vi không xác định ?!), nhưng có lẽ điều này không thể được thực hiện cho tương thích ngược hoặc các lý do khác. giải pháp tốt nhất mà tôi đã tìm thấy là để ngăn chặn nó với perlcritic:

http://search.cpan.org/perldoc?Perl::Critic::Policy::Variables::ProhibitConditionalDeclarations

+0

Perlcritic không bao giờ là giải pháp tốt nhất cho bất cứ điều gì. – tchrist

+3

Tôi có cách thay thế nào, nếu tôi muốn ngăn chặn cấu trúc độc hại này khỏi bị vô tình sử dụng? –

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