2015-09-04 16 views
5

Mam podprogram z prototypem takich jak to:Subroutine z hash i opcjonalnym skalarnego argumentu

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

Ale chciałbym ewentualnie podanie w drugim skalarnego argumentu takiego:

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

I Rozumiem, że w trybie ostrzegawczym jest to nie-nie, ale nie jestem pewien dlaczego.

Przypuszczam, że mogę użyć flagi zmiennej globalnej, ale jakiejkolwiek porady, jak elegancko wykonać tego typu podpis funkcji?

+1

Można przekazać odwołanie do skrótu zamiast samego skrótu. –

+5

Prototypy nie służą do tworzenia sygnatur funkcji, ale mają funkcje zachowujące się jak wbudowane funkcje. Generalnie radzimy, gdy chodzi o prototypy, nie należy ich używać. Funkcja zgarnie wszystkie @_ do% hashFoo. Możesz sprawdzić długość @_ i wyrzucić opcjonalny argument przed rozpakowaniem go na% hashFoo. – xxfelixxx

+1

Najczystszym rozwiązaniem byłoby dodanie opcjonalnego argumentu do reszty parametrów (foo => bar, baz => 123, specjalne => 3) i potraktowanie specjalnego parametru specjalnie (z wartością domyślną, jeśli jest to parametr nie przeszedł) – xxfelixxx

Odpowiedz

4

Nie wiem, czy to się liczy jako elegancki, ale ...

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

Prototyp z odniesieniem hash będzie również działać. Nadal powoływałbyś się na funkcję z hashem, ale musisz pamiętać, że pierwszy argument hash zostanie odebrany przez twój sub jako odniesienie hash.

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

Zgadzam się z Hakon Haegland na temat używania hash ref. Aby uzyskać więcej niż jeden argument, który możesz wybrać, musisz przekazać kilka skalarów, a nie to, co zasadniczo jest listą, po której następuje coś innego.

Myślę, że nie ma to związku z pytaniem, czy należy używać prototypów. System ostrzegania wyświadczył ci przysługę, zaznaczając to, ale mam 99,44% pewności, że nie zadziała, nawet jeśli odrzucisz prototyp. Wciąż nie otrzymasz wartości parametru opcjonalnego.

2

elegancko czynienia z opcjonalnym parametrem:

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

Jest to zbliżone do tego, jak robię to osobiście w prawie wszystkich moich modułach. Akceptuję pojedynczy href (zamiast skrótu) dla wszystkich moich paramów. Czasami przyjmuję dodatkowe wywołanie zwrotne kreacji jako wtórne arg, ale wolę akceptować wszystko w jednej strukturze. – stevieb

2

Jeśli używasz ref hash jak inni sugerowali jako pierwszy arg, a następnie sprawdzając args po ich akceptacji jest trywialne:

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

    ... 
} 
Powiązane problemy