2009-11-05 36 views
5

Với mã:Perl quyết định thứ tự nào để đánh giá các thuật ngữ trong một biểu thức?

my $x = 1; 

$x = $x * 5 * ($x += 5); 

Tôi mong chờ $x180:

$x = $x * 5 * ($x += 5); #$x = 1 
$x = $x * 5 * 6;   #$x = 6 
$x = 30 * 6; 
$x = 180; 
180; 

Nhưng thay vào đó là 30; tuy nhiên, nếu tôi thay đổi thứ tự các điều khoản:

$x = ($x += 5) * $x * 5; 

Tôi nhận được 180. Lý do tôi bối rối là perldoc perlop nói rất rõ ràng:

TERM có quyền ưu tiên cao nhất trong Perl. Chúng bao gồm các biến, các toán tử báo giá và trích dẫn tương tự, bất kỳ biểu thức nào trong dấu ngoặc đơn và bất kỳ hàm nào có đối số được đặt dấu ngoặc đơn.

Vì trong ngoặc đơn, nó phải là một thuật ngữ và do đó được thực hiện trước, bất kể thứ tự của biểu thức.

+4

Bạn biết đấy, khi đã học C trước tiên, tôi không bao giờ làm những việc như thế này và mong đợi nó hoạt động theo cách tôi nghĩ rằng nó phải hoạt động: http://c-faq.com/expr/index.html ;-) –

+3

Tôi cũng đến từ ANSI C, và yeah, đây không phải là mã tôi sẽ viết, đó là tôi cố gắng để đảm bảo rằng tôi hiểu ưu tiên trong Perl trước khi tôi giải thích nó cho người khác. Sử dụng các tác dụng phụ như thế này là một không-không lớn, nhưng vẫn hợp pháp trong Perl. Trong ANSI C, nếu bạn có nhiều hơn một tác dụng phụ trong một biểu thức kết quả là không xác định, trong tác dụng phụ Perl được xác định tốt hơn, nhưng vẫn là một ý tưởng thực sự xấu. –

+0

Tôi đã từng tạo một bài đăng đáng yêu về việc này lên comp.lang.perl.misc và chưa bao giờ có thể tìm lại nó. –

Trả lời

16

Hành vi nhập câu hỏi mang lại câu trả lời cho tôi: các cụm từ có mức độ ưu tiên cao nhất. Điều đó có nghĩa rằng $x trong đoạn đầu tiên của mã được đánh giá và mang lại 1, sau đó 5 được đánh giá và sản lượng 5, sau đó ($x += 5) là đánh giá và sản lượng 6 (với một hiệu ứng phụ của việc thiết $x-6):

$x = $x * 5 * ($x += 5); 
address of $x = $x * 5 * ($x += 5); #evaluate $x as an lvalue 
address of $x = 1 * 5 * ($x += 5); #evaluate $x as an rvalue 
address of $x = 1 * 5 * ($x += 5); #evaluate 5 
address of $x = 1 * 5 * 6;   #evaluate ($x += 5), $x is now 6 
address of $x = 1 * 5 * 6;   #evaluate 1 * 5 
address of $x = 5 * 6;    #evaluate 1 * 5 
address of $x = 30;     #evaluate 5 * 6 
30;         #evaluate address of $x = 30 

Tương tự như vậy, ví dụ thứ hai giảm như thế này:

$x = ($x += 5) * $x * 5; 
address of $x = ($x += 5) * $x * 5; #evaluate $x as an lvalue 
address of $x = 6 * $x * 5;   #evaluate ($x += 5), $x is now 6 
address of $x = 6 * 6 * 5;   #evaluate $x as an rvalue 
address of $x = 6 * 6 * 5;   #evaluate 5 
address of $x = 36 * 5;    #evaluate 6 * 6 
address of $x = 180;    #evaluate 36 * 5 
180;        #evaluate $x = 180 
+7

Chính xác. Những gì đã vấp ngã bạn không phải là ưu tiên mà là thứ tự đánh giá. '($ X + = 5)' không được đánh giá cho đến sau khi phép nhân đầu tiên diễn ra. Các dấu ngoặc đơn chỉ phục vụ để đảm bảo rằng '+ =' xảy ra trước phép nhân (thứ hai). Trong trường hợp này, điều đó ngăn ngừa lỗi cú pháp vì phép nhân có ưu tiên cao hơn phép gán và kết quả của phép nhân không phải là một giá trị hợp lệ. –

4

$x bởi chính nó cũng là một HẠN. Vì nó gặp phải đầu tiên (trong ví dụ đầu tiên của bạn), nó được đánh giá đầu tiên.

9

Bất cứ khi nào tôi có nhầm lẫn về những thứ như thế này đầu tiên tôi kéo ra perldoc perlop, và sau đó nếu tôi vẫn không chắc chắn, hoặc muốn xem cách một khối mã cụ thể sẽ được thực hiện, tôi sử dụng B::Deparse:

perl -MO=Deparse,-p,-q,-sC 
my $x = 1; 
$x = $x * 5 * ($x += 5); 

^D

cho:

(my $x = 1); 
($x = (($x * 5) * ($x += 5))); 
- syntax OK 

giá trị Vì vậy, thay thế tại mỗi giai đoạn cho:

($x = (($x * 5) * ($x += 5))); 
($x = ((1 * 5) * ($x += 5))); 
($x = ((5) * (6))); # and side-effect: $x is now 6 
($x = (5 * 6)); 
($x = (30)); 
($x = 30); 
$x = 30; 

Vì vậy, thực tế là $ x đã tạm thời thiết lập để 6 không thực sự ảnh hưởng đến bất cứ điều gì, bởi vì giá trị trước đó (1) đã được thay thế vào biểu thức, và đến cuối của biểu thức nó bây giờ là 30.

+0

Thú vị. Nhưng nó đưa ra câu hỏi mà các parens xung quanh $ x * 5 đến từ. – innaM

+4

'*' là toán tử nhị phân đánh giá từ trái qua phải, vì vậy '$ x * $ y * $ z' sẽ đánh giá là' (($ x * $ y) * $ z) '. – Ether

+0

Ether, * đánh giá * trái sang phải không giống như * liên kết * trái sang phải. Ngay cả khi '*' liên kết từ phải sang trái, nó vẫn có thể được đánh giá từ trái sang phải: đầu tiên đánh giá $ x và lưu trữ giá trị của nó trong một tạm thời; sau đó đánh giá $ y, sau đó $ z; tiếp theo nhân chúng và nhân kết quả với giá trị tạm thời được lưu từ $ x. Ưu tiên không xác định thứ tự đánh giá, trừ khi bạn có thể tìm thấy một số tài liệu có nội dung khác cho Perl. (Java, ví dụ, được định nghĩa để đánh giá từ trái sang phải, ngay cả khi một toán tử bên phải có ưu tiên cao hơn.) –

2

Tính kết hợp của toán tử * là trái, vì vậy, thuật ngữ lâu dài nhất luôn được đánh giá trước thời hạn phù hợp nhất.Các toán tử khác, chẳng hạn như ** là kết hợp phù hợp và sẽ đánh giá ($x += 5) trước phần còn lại của câu lệnh.

+0

Bạn đang conflating associativity, ưu tiên, và thứ tự đánh giá. Chúng là ba điều riêng biệt. –

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