foreach を last で抜けるとループ変数の値は保存されない

変数をループで回しながら、特定の条件にマッチしたところでループを抜け出し、条件にあった変数値を得たい、というときがある。そんなとき、次のようなコードを書いていた。

use strict;
use warnings;

my @candidates = qw/this is a test/;
my $code;
PREF:
foreach $code (@candidates) {
    last PREF if length($code) == 1;
}
print "$code\n";

実行結果は

[takeyuki@sunya ~]$ perl a.pl
Use of uninitialized value in string at a.pl line 10.

$pref_code に値が保存されていない。last で foreach を抜ける、ということは foreach に与えられたリストすべてについての処理を抜けるってことだよね、このループの中で使っていた変数は要らないよね、ということだろうか。

回避するためには、ループ変数とあとで値を使う変数とを明示的にわける必要がある。

use strict;
use warnings;

my @candidates = qw/this is a test/;
my $code;
PREF:
foreach my $c (@candidates) {
    if (length($c) == 1) {
        $code = $c;
        last PREF;
    }
}
print "$code\n";

while を使っても余計な変数が増えるだけで、わかりやすくはならない。

use strict;
use warnings;

my @candidates = qw/this is a test/;
my $last_index = $#candidates;
my $code;
my $index = 0;
PREF:
while ($index <= $last_index) {
    my $c = $candidates[$index];
    if (length($c) == 1) {
        $code = $c;
        last PREF;
    }
    $index++;
}
print "$code\n";