2008-11-04 26 views
7

Dưới đây là một số Perl đơn giản để đếm số lần một giá trị xuất hiện trong một mảng. Điều này chạy mà không có bất kỳ cảnh báo nào.Khi nào thì Perl tự động khởi tạo biến?

use warnings; 
use strict; 

my @data = qw(1 1 2 3 4 5 5 5 9); 
my %histogram; 
foreach (@data) 
{ 
    $histogram{$_}++; 
} 

Khi cơ thể loop được thay đổi để

$histogram{$_} = $histogram{$_} + 1; 

Perl cảnh báo "Sử dụng giá trị chưa được khởi tạo ngoài".

Điều gì đang xảy ra dưới mui xe? Tại sao giá trị được khởi tạo khi được cung cấp dưới dạng toán hạng cho toán tử ++ và uninitialized với toán tử +?

Trả lời

14

Toán tử + đánh giá cả biểu mẫu ở bên trái và biểu mẫu ở bên phải biểu mẫu, sau đó trả về tổng của cả hai. Đánh giá cuộc gọi băm không thấy bất kỳ ngữ cảnh đặc biệt nào.

Nhà điều hành ++ có một số ma thuật đặc biệt được xây dựng trong Trích dẫn từ manpage perlop, liên quan đến việc điều hành ++:.

"undef" luôn được coi là số, và đặc biệt được thay đổi thành 0 trước incrementing (để tăng sau một giá trị undef sẽ trả về 0 chứ không phải là "undef").

chỉnh sửa: Để giải thích sự khác biệt, ++ thay đổi giá trị tại chỗ, trong khi + chỉ lấy đối số làm đầu vào. Khi + nhìn thấy một giá trị không xác định, thường có điều gì đó sai, nhưng với ++, ví dụ thao tác băm của bạn là rất điển hình - người dùng muốn xử lý undef là 0, thay vì phải kiểm tra và khởi tạo mọi lúc. Vì vậy, có vẻ như nó có ý nghĩa để điều trị các nhà khai thác theo cách này.

7

Nó không phải là Perl nhất thiết phải khởi tạo giá trị, nhưng nó không phải lúc nào cũng cảnh báo về chúng. Đừng cố gắng suy nghĩ về một quy tắc cho điều này bởi vì bạn sẽ luôn luôn tìm thấy trường hợp ngoại lệ, và chỉ khi bạn nghĩ rằng bạn có nó đã tìm ra, phiên bản tiếp theo của Perl sẽ thay đổi cảnh báo về bạn.

Trong trường hợp này, như Harleqin cho biết, các toán tử tăng tự động có trường hợp đặc biệt.

0

Như Brian đã đề cập: nó vẫn hoạt động, nó chỉ cảnh báo bạn. Cảnh báo cho bạn biết về các thao tác nhất định với các hiệu ứng bạn có thể không có ý định.

Bạn đặc biệt yêu cầu cho giá trị $histogram{$_}, thêm 1 vào số đó và sau đó gán nó vào cùng một vị trí. Đó là cách mà tôi sẽ không mong đợi autovivification để làm việc ở đây:

my $hash_ref = $hash_for{$key_level_1}; 
$hash_ref->{$key_level_2} = $value; 

như nó ở đây:

$hash_for{$key_level_1}{$key_level_2} = $value; 

kỳ diệu có thể không hoạt động như tối ưu hóa. Và tối ưu hóa trình biên dịch sẽ nhận thấy rằng a = a + 1 giống như a++ sao cho có toán tử gia tăng trong ngôn ngữ assembly, nó có thể sử dụng lệnh được tối ưu hóa đó thay vì giả vờ rằng nó cần bảo tồn giá trị đầu tiên, và ghi đè nó bởi vì nó không 't thực sự cần thiết.

Tối ưu hóa được giám sát thêm và chi phí một lần để cải thiện hiệu suất mỗi lần chạy. Nhưng không có sự đảm bảo nào trong một ngôn ngữ động mà bạn không bổ sung thêm chi phí ở cùng mức mà bạn sẽ cố gắng giảm nó.

+0

Trong khi cảnh báo không trực tiếp phá vỡ bản dựng, chúng vẫn cần được chú ý. – Svante

7

Một số nhà khai thác cố tình bỏ qua cảnh báo "uninitialized" để thuận tiện cho bạn vì chúng thường được sử dụng trong trường hợp giá trị mặc định 0 hoặc "" cho toán hạng trái hoặc chỉ có ý nghĩa.

Đây là: ++ và - (trước hoặc sau), + =, - =,. =, | =,^=, & & =, || =.

Lưu ý rằng một số trong số này đưa ra cảnh báo sai khi được sử dụng trên biến số liên kết: xem các bài kiểm tra được đánh dấu TODO theo số http://perl5.git.perl.org/perl.git/blob/HEAD:/t/op/assignwarn.t.

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