2015-09-04 15 views
5

Ich habe ein Unterprogramm mit einem Prototyp wie folgt aus:Unterprogramm mit Hash und optional skalaren Argument

sub printFoo(%) { 
    my (%hashFoo)[email protected]_; 
    # do stuff with the hash 
} 

Aber ich möchte Pass in einer zweiten skalaren Argument wie dies optional:

sub printFoo(%;$) { 
    my (%hashFoo,$optionalArg)[email protected]_; 
    # do stuff with the hash and the optional arg 
} 

I Verstehen Sie, dass dies im Warnmodus ein Nein ist, aber ich bin mir nicht sicher warum.

Ich nehme an, ich könnte ein globales Variablenflag verwenden, aber irgendeinen Ratschlag, wie man diese Art von Funktionssignatur elegant erreicht?

+1

Sie könnten anstelle des Hashs selbst einen Verweis auf den Hash übergeben. –

+5

Prototypen dienen nicht zum Erstellen von Funktionssignaturen, aber Funktionen verhalten sich wie integrierte Funktionen. Der allgemeine Ratschlag, wenn es um Prototypen geht, besteht darin, sie nicht zu verwenden. Die Funktion wird alle @_ in% HashFoo aufheben. Sie können die Länge von @_ überprüfen und das optionale Argument abbrechen, bevor Sie es in% hashFoo entpacken. – xxfelixxx

+1

Die sauberste Lösung wäre, das optionale Argument einfach in den Rest der Parameter (foo => bar, baz => 123, special => 3) aufzunehmen und den speziellen Parameter speziell zu behandeln (mit einem Standard, wenn es das ist) nicht weitergegeben) – xxfelixxx

Antwort

4

Ich weiß nicht, ob dies so elegant zählt, aber ...

sub printFoo { 
    my $optionalArg; 
    if (@_ % 2 != 0) { 
     $optionalArg = pop @_; 
    } 
    my %hashFoo = @_; 
    ... 
} 

Ein Prototyp mit einem Hashreferenz auch funktionieren würde. Sie würden die Funktion immer noch mit einem Hash aufrufen, aber Sie müssen sich daran erinnern, dass der erste Hash-Arg von Ihrem Sub-Server als Hash-Referenz empfangen wird.

sub printFoo (\%;$) { # call as printFoo %foo or printFoo %foo, 42 
    my ($hashFooRef, $optionalArg) = @_; 
    my %hashFoo = %$hashFooRef; 
    ... 
} 
1

Ich stimme mit Hakon Haegland über einen Hash-ref verwendet wird. Um mehr als ein Argument zu erhalten, das Sie auswählen können, müssen Sie mehrere Skalare übergeben, anstatt einer Liste, auf die etwas anderes folgt.

Ich denke, dass dies unabhängig von der Frage ist, ob Sie Prototypen verwenden sollten oder nicht. Das Warnsystem hat Ihnen einen Gefallen getan, indem Sie dies gemeldet haben, aber ich bin zu 99.44% sicher, dass es nicht funktioniert, selbst wenn Sie den Prototyp verwerfen. Sie werden immer noch nicht mit einem Wert in Ihrem optionalen Parameter enden.

2

elegant mit einem optionalen Parameter handelt:

sub do_something { 
    my (%params) = @_; 
    my $debug = delete $params{debug} || 0; 
    # do something with %params... 
} 
+0

Das ist nahe daran, wie ich es persönlich in fast allen meinen Modulen mache. Ich akzeptiere einen einzigen href (anstelle eines Hash) für alle meine params. Manchmal akzeptiere ich einen zusätzlichen CRF-Rückruf als sekundäres Argument, aber ich bevorzuge es, alles in einer Struktur zu akzeptieren. – stevieb

2

Wenn Sie einen Hash-ref verwenden als andere als die erste arg vorgeschlagen haben, dann die args überprüft, nachdem sie akzeptiert werden, ist trivial:

use strict; 
use warnings; 

my %hash = (a => 1, b => 2,); 
my $scalar = 1; 

printFoo(\%hash, $scalar); 

sub printFoo { 
    my ($href, $opt) = @_; 

    if(ref $href ne 'HASH' || $opt && ref \$opt ne 'SCALAR'){ 
     die "Usage: printFoo(hashref, optional_scalar)\n"; 
    } 

    ... 
} 
Verwandte Themen