一行内简洁的foreach表达式

6
在Perl中,通常可以避免使用控制块,例如:
print "$_\n" foreach(@files);

替代:

foreach(@files){
  print "$_\n";
}

在以下更复杂的情况下,这个语法是如何工作的:
die("Not a file: $_") unless -f $_ foreach(@files);

它给了我一个语法错误。我并不想写混淆的代码,只是程序中不重要的一部分,所以我想尽可能简洁地表达它。

总结:

我只能接受一个答案作为被采纳的答案,但我最喜欢 Chris 和 Jon 提供的答案。

这个答案使用了 foreach,正如我想象的那样,但没有出现 语法错误

-f or die "Not a file: $_" foreach @files;

接下来这个至少和前面那个一样好。我喜欢die在语句开头的位置,因为读者的注意力应该集中在这里:

die("Not a file: $_") for grep {!-f} @files;

我同意die()最好放在行的开头,但是在紧急情况下,对我来说短路逻辑也同样易读。 - Chris Lutz
1
你只是在打高尔夫吗?否则,为什么将它放在一行很重要? - brian d foy
7个回答

13

为了更符合 Perl 风格(TMTOWTDI),你可以使用逻辑短路:

-f or die "Not a file: $_" foreach @files;

在 OS X 上测试过并且可用。

另外,-f or die 看起来很像我在 Perl 中看到的许多常见的 open() or die 结构,仍然(我认为)表明了该行的意图(在某些条件下 die)。


1
非常整洁。++和万岁瑞士军刀链锯! - Brent.Longborough
我喜欢它。与open()或die()的并行有点不太一样,因为open()的目的通常是打开文件而不是die()。但是,如果你认为上面代码的目的是测试文件的存在,则并行是准确的。这是一个棘手的问题,但我认为我更喜欢你的方法。;-) - Jon Ericson

11
你可以使用@Brent.Longborough的答案,或者如果你真的想要使用后缀表达式,可以这样做:
do { die("Not a file: $_") unless -f $_ } foreach(@files);

然而,我同意其他人的看法,仅仅因为这是“不重要的部分”,并不意味着简洁就更好。可读性很重要。可读性必须得到关注。


我并没有说这段代码是“不可读的”。然而,我确实断言使用链接后缀控制结构会使其更加难以阅读。当然,这是主观的。关键是,OP并没有说他试图最大化可读性,而是因为它“不重要”,所以应该“简洁”。 - Adam Bellaire

7

虽然你可能没有打算写混淆代码,但我认为你肯定在尝试。

用两行(甚至像Brent.Longborough建议的一行块)代替一行会有什么不好呢?老实说,这就是我通常讨厌尝试调试/编辑其他人perl代码的原因,很多写perl的人似乎都痴迷于用最“聪明”的方式来完成几乎所有事情,而不是以一种易于他人理解的方式来完成。


+1. 我从来不明白为什么对于一些人来说,“聪明的代码只需要一行” - innaM
1
我认为一些示例(比如使用grep的示例)是“聪明”的,但不是因为它们只有一行。它们之所以聪明,是因为它们只有一行,但清楚地显示了意义。而且看起来很好 - 嵌套的括号和方括号在一行上看起来很糟糕(在我看来(除了Lisp(哈哈)))。 - Chris Lutz

5

如果错误测试是此代码的主要点,将其放在行首可能是有意义的。稍微改进一下可以使用grep

die("Not a file: $_") for grep {!-f} @files;

但是如果您计划在代码的这部分循环遍历文件进行其他操作,那么最好将其添加到循环体中。


3

如果你不打算编写混淆代码,那就不应该像这样编写它。你正在将本应简单的东西变得难以理解。


1
这个有什么混淆的?你会怎么写? - Svante
我同意Harleqin的观点 - 这个页面上的几个答案表明有一些既清晰又一行代码的编写方法。 - Chris Lutz
我是在回复他的评论,他说“我不试图编写混淆代码”。根据韦伯斯特的定义,他的尝试是混淆的:“含糊、不明确或令人困惑”。当我发布后提交的回应含糊且令人困惑,而稍后发布的一些示例看起来还可以。 - gpojd

1
你想太多了。这是一行代码,没有任何花哨的技巧:
 foreach ( @files ) { die( "Not a file!" ) unless -f }

你可以随意调整代码块内的内容来使其更简洁,但是去掉括号和大括号并没有帮助到你,反而可能会让下一个程序员在看到后感到困惑。
不过你可能遇到了更复杂的情况,这只是一个示例。在现实世界中,事情会变得更加容易。
not_a_file_die_die_die( \@files );

然后,您将所有复杂的内容移动到子程序中。真正的诀窍是使思想意图简洁,而不是实现思想的代码。在许多情况下,机制并不重要;您更关心结果。在这些情况下,不要为机制烦恼。


0

该死,Jon 刚刚用 grep 赢了我。

但我有一个更大的问题:如果您在数组中找到一些非文件,实际上不退出程序,这怎么不重要呢?(与删除这些项、警告用户然后处理其余列表不同。)我认为终止整个程序是程序的一个相当重要的部分。

无论如何,您不能使用后缀修饰符完全按照您的意愿进行操作,因为您只能在它们的任一侧上拥有一件事情。所以你不能同时拥有 unlessforeach。从 perldoc perlsyn 的相关部分顶部:

任何简单语句都可以选择在终止分号(或块结束)之前紧跟一个单一修饰符。


是的。如果只是打印输出,传统符号表示法可能更好。但是如果可能的话,die应该是一行中的第一个标记。 - Jon Ericson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接