Perl Best Practices [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Perl Best Practices [Electronic resources] - نسخه متنی

Damian Conway

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید







6.6. Unnecessary Subscripting


Avoid subscripting arrays or hashes within loops .


Unless you actually need to know the indices of the array elements you're processing, iterate the values of an array directly:


for my $client (@clients) {
$client->tally_hours( );
$client->bill_hours( );
$client->reset_hours( );
}

Iterating the indices and then doing repeated array accesses is significantly slower, and less readable:


for my $n (0..$#clients) {
$clients[$n]->tally_hours( );
$clients[$n]->bill_hours( );
$clients[$n]->reset_hours( );
}

Repeated indexing is repeated computation; duplicated effort that incurs an extra cost but provides no added benefit. Iterating indices is also prone to off-by-one errors. For example:


for my $n (1..@clients) {
$clients[$n]->tally_hours( );
$clients[$n]->bill_hours( );
$clients[$n]->reset_hours( );
}

Likewise, if you're processing the entries of a hash and you need only the values of those entries, don't iterate the keys and then look up the values repeatedly:


for my $original_word (keys %translation_for) {
if ( $translation_for{$original_word} =~ m/ $PROFANITY /xms) {
$translation_for{$original_word} = '[DELETED]';
}
}

Repeated hash look-ups are even more costly than repeated array indexing. Just iterate the hash values directly:


for my $translated_word (values %translation_for) {
if ( $translated_word =~ m/ $PROFANITY /xms) {
$translated_word = '[DELETED]';
}
}

Note that this last example works correctly because, in Perl 5.6 and later, the values function returns a list of aliases to the actual values of the hash, rather than just a list of copies (see "Hash Values" in Chapter 8). So if you change the iterator variable (for example, assigning '[DELETED]' to $translated_word), you're actually changing the corresponding original value inside the hash.

The only situation where iterating values doesn't work correctly is when you need to delete the entries from the hash:


for my $translated_word (values %translation_for) {
if ( $translated_word =~ m/ $PROFANITY /xms) {
delete $translated_word; # Compile-time error
}
}

Here, aliasing isn't enough, because the delete builtin needs to know the key as well, so it will only accept actual hash look-ups as arguments. The correct solution is to use a hash slice instead (see Chapter 5):


my @unacceptable_words
= grep {$translation_for{$_} =~ m/ $PROFANITY /xms}
keys %translation_for;
delete @translation_for{@unacceptable_words};

The grep collects all those keys whose values must be removed, and stores that list in @unacceptable_words. The list of keys is then used to create a slice of the original hash (i.e., a list of hash look-ups), which

can be passed to delete.


By Any Other Name . . .


An alias may sometimes seem like magic, but it's based in a very simple idea.

In a Perl program, a normal variable consists of two distinct components: a storage location in memory, and a name (such as $foo) by which the program refers to that storage location. In other words, every variable is a box, with a "Hi-my-name-is..." sticker on it.

Aliasing is the process of putting a second (or third, or

n th) "Hi-my-name-is-also..." sticker on a single box. Perl subroutines do this all the time. For example, if you call get_passwd($user), then inside the call to get_passwd( ) the name $_[0] is temporarily attached to the container whose original name is $user. That container now has two names: one that's used inside the subroutine and one that's used outside.

Anything you do to an alias (e.g., get its value, increment it, print it, assign a new value to it) is really being done to the original variablebecause there's really only

one variable, no matter how many separate names you give it.


/ 317