2015-07-02 17 views
5

Vì vậy, tôi chỉ theo dõi xuống một lỗi có thể được chứng minh trong chương trình con nhỏ này:địa phương giá trị giữ lại biến

sub foo { 
    my $bar = shift or die "Missing bar", # <--- not a semicolon 
    my @items =(); 
    push @items, $bar; 
    return @items; 
} 

Rõ ràng là sai lầm là dòng đầu tiên của chương trình con kết thúc bằng một dấu phẩy. Điều này có một số hậu quả khá bất thường, như có thể thấy:

say foo(1); # 1 
say foo(1); # 11 
say foo(1); # 111 
say foo(1); # 1111 

Bây giờ, tôi hiểu rằng đây không phải lỗi cú pháp do cách toán tử dấu phẩy hoạt động. Tôi hiểu rằng @items không được đặt thành () vì bên phải của or không được tiếp cận. Câu hỏi của tôi là, làm thế nào một biến được khai báo với my bên trong một chương trình con cho phép dữ liệu tồn tại giữa các cuộc gọi chương trình con? Có vẻ như là my đang chuyển thành một số our bằng cách nào đó.

Trả lời

5

B::Deparse là vô giá trong cuộc tập trận như thế này:

$ perl -MO=Deparse 31191808.pl 
sub foo { 
    die 'Missing bar', my(@items) =() unless my $bar = shift @_; 
    push @items, $bar; 
    return @items; 
} 

mà làm cho này một biến thể của my $var if 0 lừa/lỗi/sự tò mò. Hiệu ứng của nó là tạo ra một biến từ vựng nhưng tĩnh, mà sẽ không được reinitialized mỗi khi foo được gọi.

3

Bạn đã phát hiện ra comma-operator

Từ perldoc perlop:

Binary "" là các nhà điều hành dấu phẩy. Trong ngữ cảnh vô hướng, nó đánh giá đối số bên trái , ném giá trị đó đi, sau đó đánh giá đối số đúng của nó và trả về giá trị đó.

Vì vậy, đây là thực sự được coi là một tuyên bố duy nhất:

my $bar = shift or die "Missing bar", my @items =(); 

Perl đánh giá LHS và loại bỏ kết quả, vì đây là một bài tập mà không thực sự loại bỏ bất cứ điều gì 1 vẫn gán cho $bar, sau đó đánh giá RHS và trả về giá trị đó. Một lưu ý quan trọng ở đây là điều này có nghĩa là @items được khởi tạo dưới dạng biến từ vựng tĩnh trong tiểu của bạn, nhưng vẫn tĩnh trên các cuộc gọi đến foo(). Tương tự như cách hoạt động của biến số state.

Tại thời điểm này trong chương trình con bạn đã chỉ định 1 đến $bar. Dòng tiếp theo là:

push @items, $bar; 

Perl đẩy $bar vào biến từ vựng tĩnh @items. Câu lệnh tiếp theo trả về một danh sách của một phần tử đơn 1.

Cuộc gọi tiếp theo đến foo tiếp tục thêm các phần tử vào @items mảng và sau đó trả về các phần tử này. Đây là lý do tại sao bạn thấy số lượng ngày càng tăng của 1 từ các cuộc gọi chương trình con của bạn.

+0

Tôi không chắc chắn về câu trả lời này. Nó không phải là một biến toàn cục. Tôi đang sử dụng nghiêm ngặt và cảnh báo và biến không thể truy cập được bên ngoài chương trình con. – AKHolland

+0

@AKHolland xin lỗi, tôi đã sửa đổi đoạn thứ hai sau khi tôi nhận ra nó không phải là toàn cục nhưng quên sửa đổi những điều sau này. –

+0

Đã hiểu, cảm ơn – AKHolland

3

Những gì bạn đang làm là rất giống với đoạn này:

use v5.14; # Implies strict 
sub foo { 
    my @something=() if 0; 
    push @something, shift; 
    say @something; 
} 

foo($_) for 1..5; 

Kết quả sẽ là:

1 
12 
123 
1234 
12345 

Trong Perl, có điều kiện khai báo một biến làm cho nó chỉ gán một giá trị bất cứ khi nào mà điều kiện là đúng. Nếu bạn đã thay đổi if 0 thành if $_[0] == 3, bạn sẽ nhận được một chuỗi số hoàn toàn khác. Đây thực sự là lỗi cũ trong Perl không thể sửa được nữa vì nhiều mã có thể phụ thuộc vào nó, nhưng nếu may mắn bạn có thể thấy cảnh báo này: "Sử dụng không được chấp nhận của tôi() trong điều kiện sai"

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