2008-10-14 22 views
24

Tôi có một số mã tự động tạo ra mà hiệu quả viết ra sau trong một loạt các địa điểm khác nhau ở một số mã:Làm thế nào tôi có thể bản địa hóa các biến Perl trong một khung ngăn xếp khác nhau?

no warnings 'uninitialized'; 
local %ENV = %ENV; 
local $/ = $/; 
local @INC = @INC; 
local %INC = %INC; 
local $_ = $_; 
local $| = $|; 
local %SIG = %SIG; 
use warnings 'uninitialized'; 

Khi mã tự động tạo ra, một số người cho rằng nó không thực sự cần thiết rằng mã là " đẹp ", nhưng tôi muốn lôi nó ra thành một chương trình con. Tuy nhiên, điều đó sẽ bản địa hóa các biến đó trong chương trình con đó. Có cách nào để bản địa hóa các biến đó trong khung ngăn xếp gọi không?

Cập nhật: Trong một mạch tương tự, sẽ tốt hơn nếu có thể chạy eval trong khung ngăn xếp cao hơn. Tôi nghĩ rằng Python đã có điều này. Sẽ tốt hơn nếu Perl cũng vậy.

+0

Bạn có chắc chắn bạn đã thấy điều này bằng Python không? Tenc's 'uplevel' xuất hiện trong đầu. Nhưng câu trả lời của hexten là tốt hơn nhiều anyway .. – cfi

Trả lời

30

Có lẽ bạn có thể sắp xếp mã sử dụng những người dân địa phương đó được tạo dưới dạng đóng cửa? Sau đó, bạn có thể perlguts

sub run_with_env { 
    my ($sub, @args) = @_; 
    no warnings 'uninitialized'; 
    local %ENV = %ENV; 
    local $/ = $/; 
    local @INC = @INC; 
    local %INC = %INC; 
    local $_ = $_; 
    local $| = $|; 
    local %SIG = %SIG; 
    use warnings 'uninitialized'; 
    $sub->(@args); 
} 

run_with_env(sub { 
    # do stuff here 
}); 

run_with_env(sub { 
    # do different stuff here 
}); 
+2

D'oh! Đó là hiển nhiên lúng túng khi nhìn lại :) Vì tôi tự động tạo mã, Đây là tầm thường. – Ovid

+0

Đó là một ý tưởng tiện lợi, đảo ngược vấn đề như thế! –

+0

Có vẻ như bạn thực sự muốn bản địa hóa% main ::. Tôi tự hỏi nếu có một cách để làm điều đó. –

3

Tôi không quá quen thuộc với Perl, vì vậy hãy tha thứ cho tôi nếu thực sự có thể. Nhưng thông thường, các biến cục bộ vào một khung ngăn xếp chỉ có sẵn trong khung ngăn xếp đó. Bạn không thể truy cập chúng từ một hoặc cao hơn (trừ khi bạn làm một số con trỏ hacky số học nhưng đó là không bao giờ được bảo đảm để thành công). Các khối khai báo biến lớn không may là bạn sẽ phải sống với nó.

QuantumPete

+1

Những biến này được xây dựng trong các biến toàn cầu. Họ không có chi phí nhận thức thông thường của các hình cầu vì chúng nổi tiếng và được xác định. Thật không may, chúng vẫn có hiệu ứng toàn cầu (như các biến toàn cầu làm) và nội địa hoá hạn chế các thay đổi đối với phạm vi hiện tại. – Ovid

+2

Ngoài ra, địa phương không có hành vi bạn đang nghĩ đến, không chính xác. địa phương cho phép bạn truy cập biến được bản địa hóa từ đó, sửa đổi, cập nhật, thay đổi và để nó tiếp tục trong ngăn xếp gọi đó làm giá trị mới/đã sửa đổi của bạn cho đến khi nó rời khỏi địa chỉ đã được bản địa hóa. –

1

Trong TCL bạn có thể sử dụng uplevel. Đối với Perl, tôi không biết.

+3

Tôi phải tự hỏi tại sao địa ngục có một mục nhập Wikipedia cho một từ khóa TCL?Tôi có nên thêm một cho giải nén bây giờ? :) – Ovid

+0

Giống như [Sub :: Uplevel] (http://search.cpan.org/perldoc?Sub::Uplevel)? Đó là những gì nó cho? – bart

+0

Tôi không nghĩ rằng Sub :: Uplevel giúp đỡ tất cả tôi sợ - "người gọi" không phải là một không gian tên. –

6

Không chắc tại sao QuantumPete bị giảm giá, có vẻ như anh ấy đã đúng với điều này. Bạn không thể nói local để khởi tạo các biến trong khối gọi. Chức năng của nó là đặc biệt, và khởi tạo/teardown rằng nó chỉ hoạt động trên khối nơi nó được chạy.

Có một số module thí nghiệm như Sub::UplevelDevel::RunBlock cho phép bạn để cố gắng "đánh lừa" caller() cho chương trình con hoặc làm một 'trở lại nhảy xa' của các giá trị cho các khung stack cao (tương ứng), nhưng không ai trong số những làm bất cứ điều gì để ảnh hưởng đến cách xử lý các biến (tôi đã thử.)

Vì vậy, bây giờ, nó thực sự trông giống như bạn sẽ phải sống với các khai báo địa phương trong phạm vi mà bạn cần chúng.

3

perldoc nói:

The "Alias" module implements localization of the basic types within 
    the caller's scope. People who are interested in how to localize 
    things in the containing scope should take a look there too. 

FWIW. Tôi đã không nhìn vào Alias.pm đủ chặt chẽ để xem điều này có thể dễ dàng như thế nào.