3

由于在 Windows 上 *.csv 不会从命令行扩展到 @ARGV 我通常最终会做类似的事情

map { glob } @ARGV获取文件名。

然而,我遇到了一个异常,只是想了解到底发生了什么。我刚刚读完“陌生土地上的陌生人”,所以我可以说我没有完全摸索!

use Modern::Perl;

# gets the filelist but then warns
say "Test 1 ", '-' x 20;
do { func($_) for map { glob } @ARGV } or warn "at least one arg expected\n";
say '-' x 27, "\n";

# works ok
say "Test 2 ", '-' x 20;
my @x = map { glob } @ARGV or warn "at least one arg expected\n";
func($_) for @x;
say '-' x 27, "\n";

# prints 2 (there are two files)
say "Test 3 ", '-' x 20;
func($_) for (map { glob } @ARGV or warn "at least one arg expected\n");
say '-' x 27, "\n";

sub func { 
  say "in func = $_[0]";
}

输出:

Test 1 --------------------
in func = t.csv
in func = t2.csv
at least one arg expected
---------------------------

Test 2 --------------------
in func = t.csv
in func = t2.csv
---------------------------

Test 3 --------------------
in func = 2
---------------------------

Test1:我不明白为什么do没有真正返回,func返回最后一个语句 is say,如果有输出则返回 true 。或者是for用作返回的那个do

测试3:显然标量上下文是隐含的,但如何?我在地图周围使用了括号?

谢谢,理查德。

4

2 回答 2

3

测试 1

for第一种情况是由于语句修饰符而评估 false (您可能认为它是无效的) 。观察:

  DB<1> x do { func($_) for map { glob } @ARGV }
in func = t.csv
in func = t2.csv
0  ''
  DB<2> x do { func 't.csv' ; func 't2.csv' }
in func = t.csv
in func = t2.csv
0  1

请注意,它是语句修饰符而不是表达式修饰符。在做出这种区分的语言中,表达式有返回值但没有语句。

Perl 就是这样一种语言。给定简单的程序

#! perl
@a = (1 for 6, 7, 8);

尝试运行它失败并出现语法错误。

foo 第 2 行的语法错误,靠近“1 for”
由于编译错误,foo 的执行中止。

您可能会在第一次测试中更直接地表达您的意图

map func($_), map glob, @ARGV or warn "at least one arg expected\n";

给出预期的输出。

测试 1 -----------------
在 func = t.csv
在函数 = t2.csv
--------------------------

测试 3

在第三种情况下,您将获得标量上下文,因为这就是Perl 的逻辑或被定义为工作的方式。

C 风格的逻辑或

二进制||执行短路逻辑或运算。也就是说,如果左操作数为真,则甚至不计算右操作数。如果计算,标量或列表上下文会向下传播到正确的操作数。

左操作数总是在二进制(标量)上下文中求值。整个表达式的上下文仅归入右操作数。

于 2012-06-07T13:56:54.647 回答
2

保持简单,并发布一个可行的、可移植的解决方案。


测试 1

您正在检查do.

它是 的结果,是for由 评估的最后一个操作do,并且for不返回任何有用的东西。


测试 2

您正在检查列表分配的结果。

标量上下文中的列表赋值评估其右侧 ( map) 返回的标量数量。


测试 3

您正在迭代or.

or返回它的 LHS(在标量上下文中评估)或它的 RHS 。那将是map在标量上下文中评估的返回值(数字)或warn(布尔值)返回的值。


您希望操作同时返回一个列表和一个数字。那是行不通的。

请注意,您需要bsd_glob,否则带有空格的路径将被破坏。(glob实际上使用了bsd_glob!)

use File::Glob qw( bsd_glob );
@ARGV = map bsd_glob($_), @ARGV if $^O eq 'MSWin32';
die if @ARGV < 2;
func($_) for @ARGV;
于 2012-06-07T15:05:46.690 回答