我正在使用Getopt :: Lucid来处理CLO,我遇到了一个有趣且意想不到的问题。以下代码:
push @clo_spec, map { Switch($_) } qw(-c -m -s -p),
map { Switch($_) } qw(--help --man --usage --version),
map { Switch($_) } qw(--debug --verbose),
map { Param($_) } keys %$rc_spec_ref
;
my $clo_o = Getopt::Lucid->getopt(\@clo_spec);
生成以下错误:
'Getopt::Lucid::Spec=HASH(0x9383847)' is not a valid option name/alias
现在,通过引用表示有效选项的字符串表达式来配置Getopt :: Lucid,然后将这些字符串传递给返回祝福哈希的六个子例程之一。每个子程序代表一种选项;开关,计数器,参数,列表或键对。
有趣的是,如果删除任何三个地图表达式,
push @clo_spec, #map { Switch($_) } qw(-c -m -s -p),
map { Switch($_) } qw(--help --man --usage --version),
#map { Switch($_) } qw(--debug --verbose),
#map { Param($_) } keys %$rc_spec_ref
;
然后一切正常。更有趣的是,如果你将每个地图表达式括在括号中,一切都可以正常工作:
push @clo_spec, (map { Switch($_) } qw(-c -m -s -p)),
(map { Switch($_) } qw(--help --man --usage --version)),
(map { Switch($_) } qw(--debug --verbose)),
(map { Param($_) } keys %$rc_spec_ref)
;
上面让我相信这个问题与Getopt :: Lucid中的错误无关。此外,我在查看地图函数的参考后考虑了上述修复,其中提到有时地图可能会与逗号混淆。 Perl将展平嵌入列表,周围的括号似乎具有描绘每个地图表达式的效果,但我真的不明白发生了什么。
有人可以解释一下吗?
答案 0 :(得分:10)
map
函数将列表作为参数并生成列表作为结果。您可以将map
语句链接在一起(将一个map
的输出作为输入提供给另一个),这是您的第一个示例。在各个map
运算符周围添加括号会破坏链。
阅读链式map
(或grep
)语句时,请从右向左阅读。
push @clo_spec,
map { Switch($_) } qw(-c -m -s -p),
map { Switch($_) } qw(--help --man --usage --version),
map { Switch($_) } qw(--debug --verbose),
map { Param($_) } keys %$rc_spec_ref;
来自map
的每个密钥的最后Param()
次来电%$rc_spec_ref
并返回结果。 map
上方Switch()
为--debug
,--verbose
,以及上一个map
的每个结果调用map
。上面的qw()
块会获得更长的参数列表,其中map
中的标记会将其他map
块的结果与它们连接起来。
在每个map
块周围添加括号会改变代码解析的方式,导致每个{{1}}被单独处理而不是以菊花链形式处理。
答案 1 :(得分:6)
$ perl -MO=Deparse push @clo_spec, map { Switch($_) } qw(-c -m -s -p), map { Switch($_) } qw(--help --man --usage --version), map { Switch($_) } qw(--debug --verbose), map { Param($_) } keys %$rc_spec_ref ; my $clo_o = Getopt::Lucid->getopt(\@clo_spec); ^D push @clo_spec, map({Switch($_);} ('-c', '-m', '-s', '-p'), map({Switch($_);} ( '--help', '--man', '--usage', '--version'), map({Switch($_);} ('--debug', '--verbose'), map({Param($_);} keys %$rc_spec_ref)))); my $clo_o = 'Getopt::Lucid'->getopt(\@clo_spec); - syntax OK
如果您对Perl解析某些内容感到困惑,B::Deparse非常棒。
在这种情况下,您可以清楚地看到每个map
不仅在您提供的qw()
上运行,而且还在map
之后运行。< / p>
答案 2 :(得分:5)
我认为发生的事情是,如果没有parens,每个地图的输出都会作为参数提供给它之前的地图。假设您只有两张这样的地图:
push @clo_spec, (map { Switch($_) } qw(-c -m -s -p)),
(map { Switch($_) } qw(--help --man --usage --version)),
最后一个执行第一个,输入Switch' - help',' - man'等.Twitch返回你期望的哈希值。然后,第一张地图执行,喂它切换'-c',' - m','s'和'-p'。但是它也会将第一个开关的结果输入它,这就解释了为什么你会得到HASH(...)不是有效选项名称的错误。
解决方案?使用parens使每个地图的参数显式[1],或使用多个推线,每个地图一个。
[1]如果你确实使用了parens,我建议不要(map ....)写地图(....),因为它会更清楚为什么那些parens。