如果foreach when语句中的最后一个when语句为false,则始终执行默认语句



在我的程序中,我将从命令行向程序传递一个file names列表,并检查每个文件是否为-executablereadablewritable。。

对于上述问题,我使用foreach-when语句。。但在使用whendefault语句时似乎存在一些问题,可能是我使用不正确,但它给了我意想不到的结果。。

这是我的代码:-

#!/perl/bin
use v5.14;
use warnings;
foreach (@ARGV) {
say "*************Checking file $_ *******************";
when (-r $_) { say "File is Readable"; continue; }
when (-w $_) { say "File is Writable"; continue; }   # This condition is true
when (-x $_) { say "File is Executable" }   # This condition is false
default      { say "None of them" }      # Executed
}

我只在前两个when中添加了一个continue,以使perl检查所有条件,而不管文件名如何。。

此外,我还没有在倒数第二个when中添加continue,因为我只希望在没有执行when的情况下执行我的default。。

这里的问题是,如果最后一个when条件为false,它将不会进入块,然后即使我的前两个when语句得到满足,它也会继续执行default

我通过更改when的顺序来检查这个问题的原因,发现如果只执行最后一个when,它将看到没有continue,因此不会执行default语句。。

因此,在上面的代码中,我交换了-x-r。。我的文件是可读的,所以本例中的最后一个when将被执行。。然后我的default语句就不执行了。。

#!/perl/bin
use v5.14;
use warnings;
foreach (@ARGV) {
say "*************Checking file $_ *******************";
when (-x $_) { say "File is Executable"; continue; }
when (-w $_) { say "File is Writable"; continue; }
when (-r $_) { say "File is Readable" }   # This condition is true
default      { say "None of them" }   # Not executed
}

所以,我想问,如何处理这种情况。。我希望它能像将given-when语句添加到Perl中那样工作
应检查所有when,如果至少执行了一个when,则跳过default。。

由于default不是"else条件",但当它总是匹配时,它可以被视为,因此它与您想要做的事情并不匹配。在您的默认条件下,您对该块中的早期匹配一无所知,并且您不能在不知道后续when是否匹配的情况下提前脱离主题化器,因此,要么你必须用一个布尔值来"破解"它,该布尔值表示较早匹配的一个,要么只将它交换为一个处理"遗留"条件的when;

foreach (@ARGV) {
say "*************Checking file $_ *******************";
when (-r $_)             { say "File is Readable";   continue; }
when (-w $_)             { say "File is Writable";   continue; }
when (-x $_)             { say "File is Executable"; continue; }
when (!-r && !-w && !-x) { say "None of them" }      
}

请注意,perl不会按文件名缓存stat结果,因此您将一遍又一遍地声明同一个文件。它确实提供了最后发布的统计数据的"_"缓存,因此您可以:

stat $file;
if ( -r _ ) { ... }
if ( -w _ ) { ... }

switch语句最好用于"其中一个将匹配"。在多个案例可能匹配的情况下使用它会导致必须滥用逻辑结构才能使其发挥作用。必须使用故障排除,并使您的案例依赖于订单,这是一个危险信号。

一个更好的选择可能是创建一个匹配数组。

for my $file (@files) {
my @flags;
push @flags, "readable"   if -r $file;
push @flags, "writable"   if -w $file;
push @flags, "executable" if -x $file;
if( @flags ) {
printf "%s is %sn", $file, join(", ", @flags);
}
else {
say "$file has no flags set";
}
}

构建一个数组具有更灵活的好副作用。你可以打印出一行或几行。它还避免了在最后再次重复所有标志,这违反了DRY原则。

另一种选择是使用do块来设置标志。

for my $file (@files) {
my $has_flags;
do { say "$file is readable";   $has_flags = 1; } if -r $file;
do { say "$file is writable";   $has_flags = 1; } if -w $file;
do { say "$file is executable"; $has_flags = 1; } if -x $file;
if( !$has_flags ) {
say "$file has no flags set";
}
}

我提到这一点主要是为了强调建立一系列比赛的优势。使用标志的缺点是,每个条件都必须立即采取行动,这使其灵活性降低。您必须重复设置一个标志,这违反了DRY,而且很容易被忘记,而对于数组,数据和标志是一样的。

最新更新