2015-09-04 2 views
5

У меня есть подпрограмма с прототипом, как это:подпрограммы с хэш и дополнительным скалярным аргументом

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

Но я хотел бы дополнительно пройти во втором скалярном аргументе, как это:

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

I понять, что в режиме предупреждения это не-нет, но я не уверен, почему.

Я полагаю, что могу использовать глобальный флаг переменной, но любые советы о том, как элегантно выполнить этот тип сигнатуры функции?

+1

Вы можете передать ссылку на хеш вместо самого хэша –

+5

Прототипы не предназначены для создания сигнатур функций, а для того, чтобы функции функционировали как встроенные функции. Общие рекомендации, когда дело доходит до прототипов, не должны их использовать. Функция будет зачерпывать все @_ в% hashFoo. Вы можете проверить длину @_ и удалить необязательный аргумент перед распаковкой в% hashFoo. – xxfelixxx

+1

Самое чистое решение состояло бы в том, чтобы необязательный аргумент просто включался в остальные (foo => bar, baz => 123, special => 3) params и просто обрабатывал специальный параметр (по умолчанию, если он не прошел) – xxfelixxx

ответ

4

Я не знаю, если это считается элегантным, но ...

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

Прототип со ссылкой хэша также будет работать. Вы все равно будете ссылаться на функцию с хешем, но вы должны помнить, что первый хэш-аргумент будет получен вашим субрежимом в качестве хеш-ссылки.

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

Я согласен с Hakon Haegland об использовании хэш-ссылки. Чтобы получить более одного аргумента, который вы можете выбрать, вам нужно передать несколько скаляров, а не то, что по существу является списком, за которым следует что-то еще.

Я думаю, что это не связано с вопросом, следует ли использовать прототипы или нет. Система оповещения сделала вам одолжение, отметив это, но я на 99.44% уверен, что она не сработает, даже если вы отбросите прототип. Вы по-прежнему не будете иметь значение в необязательном параметре.

2

Элегантно дело с дополнительным параметром:

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

Это близко к тому, как я делаю это лично практически во всех моих модулях. Я принимаю один href (вместо хэша) для всех моих параметров. Иногда я принимаю дополнительный обратный вызов cref как вторичный arg, но я предпочитаю принимать все в одной структуре. – stevieb

2

Если используется хэш-реф, как другие предложили в качестве первого арг, то проверка арг после того как они принимаются тривиальна:

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

    ... 
} 
Смежные вопросы