2012-06-06 46 views
13

Nếu đối sánh cụm từ thông dụng xảy ra bên trong một eval, các thay đổi đối với các biến liên quan đến chụp ($ 1, v.v.) không hiển thị trong môi trường bên ngoài. Đây có phải là một lỗi?

perlopperlre dường như không đề cập đến bất kỳ hạn chế nào như vậy.

Ví dụ:

use strict; use warnings; 
$_ = "hello"; 
eval '/(.*)/'; 
print "GOT: $1\n"; 

cho:

Use of uninitialized value $1 in concatenation (.) or string at -e line 1. 
GOT: 

Một bản demo ngắn gọn hơn là:

perl -we '$_="foo"; eval q(/(.*)/;) ; print "GOT:$1\n";' 

Trả lời

2

Bất kỳ biến từ vựng tuyên bố trong một eval sẽ bị mất sau khi kết thúc eval .

+1

Tôi đã từng nghĩ về '$ 1' (và' $ & ', cho vấn đề đó) dưới dạng * biến toàn cục * chứ không phải * từ * lexical *. – Lumi

+0

@Lumi chúng là toàn cầu nhưng được khai báo hoàn toàn chỉ bằng lần sử dụng đầu tiên (xem ví dụ trong câu trả lời của tôi) – Matteo

+1

@Matteo - Không, khái niệm * tuyên bố * biến toàn cầu (thực sự * gói * biến) trong Perl là gây hiểu nhầm. Không cần phải khai báo chúng, không phải những thông tin được tích hợp sẵn cũng như không có người dùng nào có thể thêm vào. Chúng chỉ là những giá trị được lưu trữ trong một không gian tên.* Cần khai báo hoặc trình độ đầy đủ * chỉ phát sinh với 'pragma' nghiêm ngặt: 'khai báo' của tôi, 'khai báo' của chúng tôi (kèm theo gói nhưng bị lốm đốm), hoặc đủ điều kiện của các hình cầu không có sẵn. – Lumi

10

Tài liệu chứng minh rằng local biến ized là những vấn đề ở đây là trong perlvar of 5.14.0:

Các biến này được chỉ đọc và tự động đặt phạm vi, trừ khi chúng ta lưu ý khác.

Bản chất năng động của các biến biểu thức chính quy có nghĩa là giá trị của chúng được giới hạn trong khối mà họ đang có trong [...]

Lưu ý rằng bit này của tài liệu là absent from the 5.12.4 perldoc.


Sự cố là local biến được đánh dấu. bản sao của tôi perldoc -f eval (5.12.4) đã cho biết:

The assignment to [email protected] occurs before restoration of localised 
variables, which means a temporary is required if you want to 
mask some but not all errors: [...] 

Các manpage không làm cho một tuyên bố rõ ràng cho tất cả các biến toàn cầu đặc biệt như vậy (như $1, $&, và có lẽ những người khác), nhưng nội địa hóa khối và phục hồi tiếp theo là gì dường như xảy ra ở đây.

Các biến được gán cho bên trong eval và các giá trị ban đầu được khôi phục sau khi chặn eval.

use strict; use warnings; 
use Test::More; 
use constant V => 'hello'; 

$_ = V; 

note '*** block eval'; 
eval { 
     is $_, V, 'input ok'; 
     /(.*)/; 
     is $&, V, 'in eval'; is $1, V, 'in eval'; 
}; 
is $&, V, 'after eval'; is $1, V, 'after eval'; 

note '*** without eval'; 
is $_, V, 'input ok'; 
/(.*)/; 
is $&, V; is $1, V; 

done_testing; 
+0

@Matteo - Như đã nêu trong một nhận xét khác trên trang này, '$ 1' không được" khai báo ngầm ". Xem phần cập nhật ở đầu câu trả lời của tôi để tham khảo tài liệu giải thích vấn đề này. – Lumi

3

Câu hỏi thực tế đã được trả lời, vì vậy, đây là câu trả lời về cách bạn đạt được nhiệm vụ.

Chỉ cần sử dụng giá trị trả về của eval, lần lượt sử dụng giá trị trả lại của toán tử đối sánh. $1 hút, tránh.

use strict; use warnings; 
$_ = "hello"; 
my @r = eval '/(.*)/'; 
# (
#  "hello" 
#) 
Các vấn đề liên quan