2011-05-14 40 views

Trả lời

7

Mảng đối số @_ không hoạt động theo cách bạn nghĩ. Các giá trị trong @_ trong một chương trình con thực sự aliases for the real arguments:

Mảng @_ là một mảng địa phương, nhưng các yếu tố của nó là bí danh cho các thông số vô hướng thực tế.

Khi bạn nói điều này:

sub s { 
    "huh?" =~ /(.*)/; 
    print for @_; 
} 

"ok" =~ /(.*)/; 
s("$1", $1); 

Các $1 trong đối số đầu tiên s ngay lập tức được đánh giá bởi các suy chuỗi nhưng đối số thứ hai không được đánh giá, nó chỉ là lưu ý rằng giá trị thứ hai trong phiên bản phụ của @_$1 (biến thực tế $1, không phải giá trị của nó). Sau đó, bên trong s, giá trị của $1 được thay đổi bằng cụm từ thông dụng của bạn. Và bây giờ, @_ của bạn có một bí danh cho chuỗi "ok" theo sau là một bí danh cho $1, các bí danh này được giải quyết bằng print trong vòng lặp của bạn.

Nếu bạn thay đổi các chức năng sau:

sub s { 
    my @a = @_; 
    "huh?" =~ /(.*)/; 
    print for @a; 
} 

hoặc ngay cả điều này:

sub s { 
    local $1; 
    "huh?" =~ /(.*)/; 
    print for @_; 
} 

Sau đó, bạn sẽ nhận được hai dòng "ok" mà bạn đang mong đợi. Hài hước (hài hước, không vui nhộn ha-ha) là hai phiên bản của s tạo ra kết quả mong đợi của bạn vì những lý do khác nhau.Phiên bản my @a = @_; chiết xuất các giá trị hiện tại của các bí danh trong @_ trước khi cụm từ thông dụng được đặt trên $1; các local $1; version localizes biến $1 cho phụ rời khỏi bí danh trong @_ tham khảo phiên bản của $1 từ bên ngoài phụ:

Một Sửa địa phương các biến được liệt kê là địa phương để các khối kèm theo, tập tin, hoặc eval.

điều lạ như thế này là lý do tại sao bạn nên luôn luôn sao chép các giá trị của các biến thu thập regex đánh số cho các biến của bạn càng sớm càng tốt và tại sao bạn muốn giải nén @_ ngay từ đầu các chức năng của bạn (trừ khi bạn biết lý do tại sao bạn không muốn làm điều đó).

Hy vọng rằng tôi đã không giết thuật ngữ quá nhiều, đây là một trong những góc kỳ lạ của Perl mà tôi đã luôn luôn tránh xa vì tôi không thích tung hứng lưỡi dao cạo.

2

Mẫu mã tận dụng hai sự kiện:

  • Các yếu tố của mảng @_ là bí danh cho các thông số vô hướng thực tế. Đặc biệt, nếu một phần tử $_[0] được cập nhật, đối số tương ứng được cập nhật (và ngược lại).
  • $1 là biến toàn cầu (mặc dù được tự động dò tìm đến BLOCK hiện tại), tự động chứa mẫu con từ () từ kết quả mẫu khớp thành công cuối cùng.

Đối số đầu tiên cho chương trình con là chuỗi thông thường ("ok"). Đối số thứ hai là biến toàn cục $1. Nhưng nó được thay đổi bởi sự khớp mẫu thành công bên trong chương trình con, trước khi các đối số được in.

1

Điều đó xảy ra vì perl chuyển tham số bằng tham chiếu.

Những gì bạn đang làm là tương tự như:

my $a = 'ok'; 

sub foo { 
    $a = 'huh?'; 
    print for @_; 
} 

my $b = $a; 
foo($b, $a) 

Khi foo phụ được gọi là, $ _ [1] thực sự là một bí danh cho $ a và vì thế giá trị của nó được sửa đổi khi $ a được sửa đổi.