您的代码中存在逻辑错误。出于演示的目的,我将从使用STDIN 作为您的输入句柄切换到使用DATA 的位置,以便我可以烘焙一些测试数据。我还将删除外部子程序,因为它与讨论无关。
use strict;
use warnings;
my %profession = (
Emelie => 'Economist',
Hugo => 'Scientist',
Maria => 'Accountant',
Linnéa => 'Medical Doctor',
);
chomp(my $name = <DATA>);
my $var = 1;
while($var) {
if (exists $profession{$name}) {
print "The profession for $name is $profession{$name}\n";
$var = 0; # This could just be the 'last' keyword.
}
else {
print "No such name ($name) found. Try again.\n";
}
}
__DATA__
John
Dave
Maria
正如您从示例数据中看到的那样,您会期望具有正确逻辑的程序在第三次尝试后终止,因为Maria 是您的哈希键之一。但如果你运行它,你会看到:
No such name (John) found. Try again.
No such name (John) found. Try again.
No such name (John) found. Try again.
No such name (John) found. Try again.
No such name (John) found. Try again.
No such name (John) found. Try again.
No such name (John) found. Try again.
No such name (John) found. Try again.
^C
Command terminated
(^C 和 Command terminated 行来自我最终点击 -c 终止运行时。)
此时,通过打印最近从<DATA> 读取的名称的附加信息,很容易看出我们只在查看John。但为什么?因为您的循环不会从 <DATA> 文件句柄中读取。你是在循环之外做的。
这里有一个更 Perlish 的方式来完成你想做的事情:
use strict;
use warnings;
my %profession = (
'Emelie' => 'Economist',
'Hugo' => 'Scientist',
'Maria' => 'Accountant',
'Linnéa' => 'Medical Doctor',
);
while(my $name = <DATA>) {
chomp $name;
if (exists $profession{$name}) {
print "The profession for $name is $profession{$name}\n";
last;
}
print "No such name ($name) found. Try again.\n";
}
__DATA__
John
Dave
Maria
现在输出将是:
No such name (John) found. Try again.
No such name (Dave) found. Try again.
The profession for Maria is Accountant
第一次通过这个while循环我们从DATA读取并获得John\n。我们将它分配给$name、chomp 它,然后检查John 是否作为哈希键存在。它没有,所以我们打印名称并继续下一次迭代。在第二次迭代中,<DATA> 读取 Dave\n,将其切碎并检查它是否存在。它没有,所以我们打印名称并继续下一次迭代。
在第三次迭代中,我们<DATA> 获得Maria\n,将其切碎,并检查是否存在哈希键Maria。它确实如此,因此它打印与该键关联的值,然后点击last 语句。 last 告诉流控制立即退出封闭循环。循环主块中的其余行被跳过,不再有迭代。它通常比示例代码中的 $var 等标记变量更易读,因为代码的读者无需跟踪变量可能处于的状态。
简而言之,你的错误是只从输入文件句柄中读取一次,然后期望你的循环在进入循环之前遇到$name 的变化,尽管它只被分配了一次。解决方案是将读取的文件移动到循环中。
此模式记录在 perldoc perlvar 中,我鼓励您花几分钟时间阅读以更好地熟悉该语言。
更新:我确实看到了一个答案,其中再次调用 main() 用作迭代读取的文件的一种方式,这并没有错。但是在真正的脚本中main() 可能会变得更大,当这种情况发生时,文件读取循环要么需要再次成为显式循环,要么被分解为可以调用自身的不同子例程。此外,while 循环方法是一种惯用或常见的解决方案,更有可能在其他人编写的代码中找到。使用递归读取文件是一种不太常见的模式。