perl GetOptions,接受参数的选项触发子例程



我正试图使用GetOpt::Long中的GetOptions函数来调用接受参数的子例程。但是,无论是否在命令行上指定了该选项,都会调用该子例程。如果在GetOptions行中没有将参数传递给子例程,则不会发生这种意外行为。

以下是对问题的最低限度的演示:

如果在GetOptions行中为子程序提供了一个自变量,则无论其控制选项是否在命令行上提供,子程序最终都会被调用:

$ cat a1.pl
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long qw(GetOptions);
my $var="entered";
GetOptions ( "opt" => &sub1($var) );
sub sub1 { print "sub1 $_[0]n"; }
$ perl a1.pl --opt
sub1 entered
$ perl a1.pl
sub1 entered

相反,如果在GetOptions中调用子例程而不带参数,则其行为适当:

$ cat a2.pl
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long qw(GetOptions);
GetOptions ( "opt" => &sub2 );
sub sub2 { print "sub2 enteredn"; }
$ perl a2.pl --opt
sub2 entered
$ perl a2.pl

我做错了什么?

PS:我知道我可以简单地设置一个变量来控制是否在GetOptions块之后调用子例程,但我想确定在GetOptions行中调用子例程的正确语法,并了解观察到的行为发生的原因。

模块需要一个代码引用,该代码引用单独使用子名称(&name)或作为匿名子;不存在";论点";因为您不是在进行函数调用,而是在获取(对代码的)引用。然后用那个代码调用你的sub。详情如下。

将该选项与一个匿名子程序关联,在该子程序中您可以调用您的子

use warnings;
use strict;
use feature 'say';
use Getopt::Long;
my $opt;
my $var = 'entered';
GetOptions ( 'opt' => sub { $opt = 1; sub1($var) } );
sub sub1 { say "sub1 $_[0]"; }

或者使用'opt' => &cb并在子cb()中调用sub1(...)。此回调传递选项名称和值(或者在哈希的情况下传递名称、键和值),并且不接受其他参数。因此,您无法以任何方式动态解析传递给sub1()的参数。

问题中的调用不是如何获得子例程引用;您只能使用子例程名称&name。这与Getopt无关,它只是想要一个代码参考。

当你试图";传递参数";它不再是coderef,而是执行sub,然后引用它的返回;与CCD_ 15或CCD_。这可以通过看到

perl -wE'sub tt { say "@_"; return "ret" }; $r = &tt("hi"); say $$r'

什么打印

hiret

虽然这不是一种获取参考的方式,但让我仍然警告可能出现的意外(如果一个人最终试图获取"列表参考")

我已经有几年没有做过很多Perl了,但我很确定这是因为

&sub1($var)

是对调用sub1结果的引用。即线

GetOptions ( "opt" => &sub1($var) );

实际上调用CCD_ 18作为构造CCD_。这看起来像是语法中的一个角落案例,您正在引用该调用的结果。

这应该会澄清问题:

$ perl -de0
Loading DB routines from perl5db.pl version 1.49_001
Editor support available.
Enter h or 'h h' for help, or 'man perldebug' for more help.
main::(-e:1):   0
DB<1> sub sub1 { print "sub1n"; }
DB<2> sub1()
sub1
DB<3> &sub1
sub1
DB<4> &sub1
DB<5> x &sub1
0  CODE(0x804d7fe8)
-> &main::sub1 in (eval 6)[/usr/lib/perl5/5.22/perl5db.pl:737]:2-2
DB<6> x &sub1()
sub1
0  SCALAR(0x804ee7f0)
-> 1

最新更新