Perl 提供了多种循环控制结构,既有传统风格的,也有更现代的。以下是 Perl 循环的详细总结:
1. 传统 C 风格 for 循环
for (my $i = 0; $i < 10; $i++) {
print "$i\n";
}
2. foreach 循环
# 遍历数组
my @array = (1..10);
foreach my $item (@array) {
print "$item\n";
}
# 简写:for 和 foreach 可互换
for my $num (1..5) {
print "$num\n";
}
# 直接使用默认变量 $_
foreach (@array) {
print "$_\n"; # $_ 是当前元素
}
3. while 循环
# 条件循环
my $count = 0;
while ($count < 5) {
print "$count\n";
$count++;
}
# 读取文件行
while (my $line = <FILE>) {
chomp $line;
print "$line\n";
}
# 使用默认变量
while (<FILE>) {
print; # 默认打印 $_
}
4. until 循环
my $i = 0;
until ($i >= 5) { # 直到条件为真
print "$i\n";
$i++;
}
5. do...while 和 do...until
# do...while (至少执行一次)
my $x = 10;
do {
print "$x\n";
$x--;
} while ($x > 0);
# do...until
my $y = 0;
do {
print "$y\n";
$y++;
} until ($y >= 5);
6. 循环控制语句
# last - 类似 break
foreach my $i (1..10) {
last if $i == 5; # 在 5 时退出循环
print "$i\n";
}
# next - 类似 continue
foreach my $i (1..5) {
next if $i == 3; # 跳过 3
print "$i\n";
}
# redo - 重新执行当前迭代
my $attempts = 0;
while ($attempts < 3) {
print "输入 y/n: ";
my $input = <STDIN>;
chomp $input;
if ($input !~ /^[yn]$/i) {
print "无效输入,重试\n";
$attempts++;
redo; # 不增加循环计数器,重新开始当前迭代
}
# 处理有效输入...
}
# 带标签的循环
OUTER: for my $i (1..3) {
INNER: for my $j (1..3) {
last OUTER if $i == 2 && $j == 2;
print "($i, $j)\n";
}
}
7. 循环中的特殊变量
# 循环控制变量
for my $i (1..5) {
print "当前索引: $i\n";
}
# 使用列表切片
my @list = qw(a b c d e);
for my $index (0..$#list) {
print "索引 $index: $list[$index]\n";
}
8. map 和 grep (函数式循环)
# map - 转换列表
my @squares = map { $_ * $_ } 1..10;
# grep - 过滤列表
my @evens = grep { $_ % 2 == 0 } 1..100;
# 组合使用
my @result = map { $_ * 2 }
grep { $_ > 5 }
1..10;
9. 范围操作符在循环中
# 数字范围
for (1..10) { print "$_\n"; }
# 字母范围
for ('a'..'z') { print "$_\n"; }
# 作为数组下标
for (0..$#array) {
print "$array[$_]\n";
}
10. 无限循环
# 多种方式实现无限循环
while (1) {
# 处理逻辑
last if $condition;
}
for (;;) {
# 传统 C 风格
last if $condition;
}
# 使用标签
INFINITE: {
print "循环中...\n";
sleep 1;
redo INFINITE;
}
实际应用示例
#!/usr/bin/perl
use strict;
use warnings;
# 示例1: 处理二维数组
my @matrix = (
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
);
for my $row (@matrix) {
for my $cell (@$row) {
print "$cell ";
}
print "\n";
}
# 示例2: 读取并处理文件
open my $fh, '<', 'data.txt' or die $!;
while (my $line = <$fh>) {
chomp $line;
# 跳过空行和注释
next if $line =~ /^\s*$/;
next if $line =~ /^#/;
# 处理数据
process_line($line);
}
close $fh;
# 示例3: 使用 map 和 grep
my @data = (1..20);
my @processed = map {
my $result = $_ * 2;
$result > 20 ? undef : $result
} grep {
$_ % 3 == 0
} @data;
# 移除 undef
@processed = grep { defined $_ } @processed;
sub process_line {
my $line = shift;
# 处理逻辑
}
最佳实践建议
优先使用 foreach:更清晰,避免索引错误
使用词法变量:
for my $item (@list) 而不是
for $item (@list)
避免修改循环列表:在循环中修改正在遍历的数组可能导致意外行为
合理使用 last/next:提高代码可读性
考虑使用 map/grep:对于简单转换和过滤,代码更简洁
根据具体场景选择合适的循环结构可以让 Perl 代码更清晰、高效。