2009-08-06 18 views
9

Tôi biết rằng trong một subroutine trong Perl, nó là một ý tưởng rất tốt để giữ gìn "biến mặc định" $_ với local trước khi làm bất cứ điều gì với nó, trong trường hợp người gọi đang sử dụng nó, ví dụ:

sub f() { 
    local $_;    # Ensure $_ is restored on dynamic scope exit 
    while (<$somefile>) { # Clobbers $_, but that's OK -- it will be restored 
     ... 
    } 
} 

Bây giờ , thường là lý do bạn sử dụng $_ ở nơi đầu tiên là vì bạn muốn sử dụng regexes, có thể đưa kết quả vào các biến "ma thuật" tiện dụng như $1, $2 v.v. Tôi cũng muốn giữ các biến đó, nhưng tôi đã Tôi có thể tìm cách để làm điều đó.

Tất cả perlvar nói là @+@-, mà $1, vv dường như phụ thuộc vào nội bộ, tham khảo phần "submatches thành công cuối cùng trong phạm vi năng động đang hoạt động". Nhưng ngay cả điều đó cũng có vẻ mâu thuẫn với các thí nghiệm của tôi. Theo kinh nghiệm, các bản in mã sau "aXaa" như tôi đã hy vọng:

$_ = 'a'; 
/(.)/;   # Sets $1 to 'a' 
print $1;  # Prints 'a' 
{ 
    local $_; # Preserve $_ 
    $_ = 'X'; 
    /(.)/;  # Sets $1 to 'X' 
    print $1; # Prints 'X' 
} 
print $_;  # Prints 'a' ('local' restored the earlier value of $_) 
print $1;  # Prints 'a', suggesting localising $_ does localise $1 etc. too 

Nhưng những gì tôi tìm thấy thực sự đáng ngạc nhiên là, trong ActivePerl tôi 5.10.0 ít nhất, ý kiến ​​ra dòng local vẫn giữ $1 - - đó là, câu trả lời "aXXa" được tạo ra! Dường như phạm vi từ vựng (không động) của khối ngoặc nhọn bằng cách nào đó giữ nguyên giá trị của $1.

Vì vậy, tôi thấy tình huống này khó hiểu nhất và rất thích nghe lời giải thích cuối cùng. Tâm trí bạn, tôi muốn thực sự giải quyết một cách chống đạn để bảo vệ tất cả biến kỳ diệu regex liên quan đến mà không cần phải liệt kê tất cả chúng như trong:

local @+, @-, $&, $1, $2, $3, $4, ... 

đó rõ ràng là một hack kinh tởm. Cho đến lúc đó, tôi sẽ lo lắng rằng bất kỳ regex nào mà tôi chạm vào đều sẽ làm một cái gì đó mà người gọi không mong đợi bị che khuất.

Cảm ơn!

+0

@pilcrow: tôi không bắt câu trả lời của bạn, nhưng thấy nó trong một email tóm tắt SO gửi cho tôi - tôi đoán bạn đã xóa nó? Dù sao, tôi nghĩ đó là một câu trả lời hữu ích, và nếu bạn tình cờ đọc điều này: Tôi đang tìm kiếm loại bảo quản thứ nhất. Thứ 2 thực sự là những gì tôi hy vọng sẽ * không * xảy ra - điều đó sẽ làm cho những thứ "nên" cục bộ "chảy máu" vào các phạm vi khác, và vâng, nếu tôi muốn loại "bảo quản", tôi chỉ cần sao chép $ 1 vv vào các biến địa phương khác như bạn đã đề xuất. –

Trả lời

8

Có thể bạn có thể đề xuất một từ ngữ tốt hơn cho tài liệu. Phạm vi động có nghĩa là mọi thứ bắt đầu từ khối bao quanh hoặc chương trình con, cộng với mọi thứ bắt đầu từ khối đó hoặc cuộc gọi chương trình con, v.v. ngoại trừ mà bất kỳ khối đã đóng nào đều bị loại trừ.

Một cách khác để nói: "các lần gửi thành công cuối cùng trong phạm vi hoạt động hiện đang hoạt động" có nghĩa là hoàn toàn có local $x=$x; ở đầu mỗi khối cho mỗi biến.

Hầu hết các đề cập về phạm vi động (ví dụ: http://perldoc.perl.org/perlglossary.html#scope hoặc http://perldoc.perl.org/perlglossary.html#dynamic-scoping) đang tiếp cận nó theo cách khác. Chúng áp dụng nếu bạn nghĩ về một thành công regex như ngầm thực hiện một local $1, v.v.

+4

+1. '$ 1' và vv là tự động' local() 'ized, và phạm vi là khó hiểu. – pilcrow

+0

Cảm ơn, rất hữu ích! Có, tôi đã nhầm lẫn bởi thuật ngữ "phạm vi năng động", mà (vì một lý do nào đó) tôi đã loại trừ/bỏ qua các khối. Thật dễ dàng khi biết rằng $ 1 vv được ẩn cục bộ. (Dựa trên các liên kết của bạn, tôi đoán không có gì rõ ràng trong tài liệu Perl nói như vậy?) –

3

Tôi không chắc có bất kỳ lý do thực sự nào để trở thành hoang tưởng về tất cả các biến này hay không. Tôi đã quản lý để sử dụng Perl trong gần mười năm mà không cần sử dụng một cách rõ ràng local trong ngữ cảnh này.

Câu trả lời cho câu hỏi cụ thể của bạn là: Số biến số không phải là số đã cho (mặc dù có giới hạn bộ nhớ cứng cho số lượng kết quả phù hợp với bạn). Vì vậy, không thể bản địa hóa tất cả chúng cùng một lúc.

+2

@Sanan, không hoàn toàn. Họ tất cả đã luôn luôn cục bộ() ized. Người hỏi là một chút bối rối bởi điều này và có lẽ bởi sự phức tạp của hai mô hình phạm vi trong perl. – pilcrow

+0

@ Sinan: Người gọi tiết kiệm không quy mô lớn cho hệ thống tốt bởi vì người gọi phải luôn luôn chú ý đến những gì tất cả các chức năng gọi là clobber, tất cả các con đường xuống đồ thị cuộc gọi. Vì vậy, thật dễ dàng cho một sự thay đổi trong việc thực hiện chức năng ở mức độ thấp để gây rối với chức năng cấp cao. Nó là tốt cho các kịch bản 100 dòng, nhưng nếu bạn đang viết một hệ thống lớn, bạn phải có khả năng * không quan tâm * về các chi tiết thực hiện của các hàm bạn gọi. –

+0

Nhưng, hãy xem, đó là điều: Tôi chưa bao giờ phải quan tâm đến các chi tiết thực hiện của các chức năng mà tôi gọi (tốt, chúng ta hãy quên đi 'Win32 :: OLE' một lúc). Do làm rõ của pilcrow, nó là rõ ràng lý do tại sao. –

1

Tôi nghĩ bạn đang lo lắng quá nhiều. Điều tốt nhất để làm được điều hành điều hành trận đấu của bạn, ngay lập tức lưu các giá trị bạn muốn vào các biến có ý nghĩa, sau đó để cho các biến đặc biệt làm bất cứ điều gì họ làm mà không lo lắng về họ:

if($string =~ m/...(a.c).../) { 
    my $found = $1; 
    } 

Khi tôi muốn chụp các bộ phận của chuỗi, tôi thường xuyên nhất sử dụng toán tử trận trong danh sách bối cảnh để có được một danh sách các ký ức trở lại:

my @array = $string =~ m/..../g; 
+0

Phải không đồng ý ở đó :) Trong những năm qua tôi đã nhận thấy rằng bất kỳ thực hành mã hóa có vẻ như "không" gây ra vấn đề (ví dụ như dựa vào $ 1 v.v.không thay đổi qua các cuộc gọi đến các chức năng khác), cuối cùng sẽ gây ra vấn đề * trừ khi có một đảm bảo rằng nó không thể *, vì vậy ngày nay tôi tìm kiếm bảo lãnh. Hạnh phúc, trong trường hợp này ysth đã có thể cho tôi thấy rằng Perl cung cấp sự bảo đảm như vậy. –

+0

Giả sử Perl không thực sự tự động địa phương hóa $ 1 v.v. Sau đó, thật dễ dàng để xem đoạn mã 1 của bạn dễ vỡ như thế nào: Giả sử rằng trong quá trình bảo trì, câu lệnh "if" sẽ thành "if ($ string = ~ m /...(ac).../ && some_other_test()) {...} ". Tất cả mọi thứ hoạt động tốt cho đến khi ai đó thêm một regex ở đâu đó sâu trong ruột của some_other_test(), tại thời điểm đó $ tìm thấy bắt đầu bí ẩn nhận được giá trị kỳ lạ được giao. Bạn có đồng ý rằng đây là một kịch bản bảo trì hợp lý không? –

+0

Vì vậy, một anh chàng đi vào bác sĩ và nói "Nó đau khi tôi di chuyển cánh tay của tôi như thế này!". Bác sĩ nói "Đừng di chuyển cánh tay của bạn như thế!". Đoạn mã đầu tiên của tôi không hề mong manh chút nào. Đó là sự thay đổi của bạn với nó đó là vấn đề. Tôi đã cố tình làm các hoạt động một mình. Bạn không làm những gì tôi nói: ngay lập tức lưu kết quả. –

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