2017-11-15 3 views
4

Ich versuche die GetOptions Funktion von GetOpt::Long zu verwenden, um eine Subroutine aufzurufen, die ein Argument akzeptiert. Die Subroutine wird jedoch aufgerufen, unabhängig davon, ob die Option in der Befehlszeile angegeben ist. Dieses unerwartete Verhalten tritt nicht auf, wenn ein Argument in der Zeile GetOptions nicht an das Unterprogramm übergeben wird.perl GetOptions, optiongetriggerte Subroutine, die Argumente akzeptiert

Was folgt, ist eine minimale Demonstration des Problems:

Wenn ein Argument an das Unterprogramm in der GetOptions Leitung vorgesehen ist, das Unterprogramm aufgerufen wird, endet unabhängig davon, ob seine Steuerung Option auf der Befehlszeile angegeben wird:

$ 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 

im Gegensatz dazu, wenn das Unterprogramm in GetOptions ohne Argument aufgerufen wird, verhält es sich entsprechend:

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

$ perl a2.pl --opt 
sub2 entered 

$ perl a2.pl 

Was mache ich falsch?

PS: Ich weiß, dass ich einfach eine Variable festlegen kann, die steuert, ob das Unterprogramm nach dem GetOptions-Block aufgerufen wird, aber ich möchte die richtige Syntax für den Aufruf der Unterroutine innerhalb der GetOptions Zeile, sowie verstehen, warum das beobachtete Verhalten passiert.

+4

Wow, die zweite Frage, die ich heute gesehen habe, dass tatsächlich enthält eine [MCVE]. Ich sehe zwei solche Fragen an einem Tag. Herzliche Glückwünsche! –

Antwort

1

Das Modul , und das ist mit dem Unternamen allein genommen (\&name) oder als anonyme sub; Es gibt keine Vorstellung von "Argumenten", da Sie keinen Funktionsaufruf machen, sondern eine Referenz (zum Code) erhalten. Dann rufe dich sub in diesem Code an. Details folgen.

Mitarbeiter die Möglichkeit, mit einem anonymen Unterprogramm, innerhalb dessen Sie Ihre Unter

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]"; } 

Oder 'opt' => \&cb und in der Unter cb() Aufruf aufrufen können sub1(...) verwenden. Dieser Callback übergibt den Optionsnamen und -wert (oder den Namen, den Schlüssel und den Wert im Falle eines Hashs) und nimmt keine anderen Argumente an. Sie können also nicht dynamisch bestimmen, welche Argumente an sub1() übergeben werden sollen.

Der Aufruf in der Frage ist nicht, wie ein subroutine reference erhalten wird; Sie müssen nur den Subroutinennamen \&name verwenden. Dies ist nicht etwa Getopt, die nur eine Code-Referenz will.

Wenn Sie versuchen, "Argumente" zu übergeben, die kein Coderef mehr sind, aber das Sub wird ausgeführt und dann die Referenz seiner Rückkehr genommen; wie \sub() oder \(sub()). Dies kann durch

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

welche Drucke

 
hi 
ret 

Während dies kein Weg, nur ist zu sehen einen Verweis auf nehmen lassen Sie mich noch von surprises warnen.

+0

Was ist los mit zwei downvotes ?? Wenn ich wahnsinnig und blind werde, würde mich bitte jemand wissen lassen? – zdim

1

Es ist schon ein paar Jahre her, seit ich viel Perl tat, aber ich bin mir ziemlich sicher, dass es da ist

\&sub1($var) 

ein Verweis auf das Ergebnis istsub1 von Aufrufen. Das heißt, die Linie

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

ruft tatsächlich sub($var) als Teil der Argumentliste GetOptions zu konstruieren. Das sieht wie ein Eckfall in der Syntax aus, Sie beziehen sich auf das Ergebnis dieses Aufrufs.

Dies sollte die Dinge klären:

$ 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 "sub1\n"; } 

    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 
+0

Interessant, danke. Ich habe diese Tatsache nicht geschätzt. – user001

Verwandte Themen