Как передать необязательные параметры функции Perl?

Я хочу передать несколько параметров, один из которых является необязательным, для функции. Единственный способ сделать это, что я знаю, это использовать список (@) в качестве параметра. Таким образом, он не содержит ничего или 1 элемент (никогда не будет undef), поэтому я могу использовать следующий код:

sub someFunction([email protected]) {
    my ( $oblig_param1, $oblig_param2, $option_param ) = @_;
    ...
} 

Этот код работает, но я чувствую, что, возможно, это не лучший обходной путь.
Есть ли другие способы сделать это?
Спасибо.

Ответ 1

Вы можете использовать точку с запятой в прототипе, чтобы указать конец требуемых параметров:

sub someFunction($$;$) {
  my ( $oblig_param1, $oblig_param2, $option_param ) = @_;
  ...
}

; является необязательным до @ или %, который, согласно документам, "накапливает все остальное".

EDIT: Как отмечает DVK в комментарии (и TLP подчеркивает в другом ответе здесь), вы, вероятно, лучше всего избегаете прототипов:

sub someFunction {
  my ( $oblig_param1, $oblig_param2, $option_param ) = @_;
  ...
}

Прототипы Perl имеют свои возможности (в основном для обеспечения неявного контекстного принуждения к аргументам, как это делают встроенные функции Perl). Они должны не использоваться как механизм для проверки того, что функция вызывается с правильным числом и типом аргументов.

Ответ 2

Prototypes (часть ([email protected]) вашего дополнительного объявления) являются необязательными. Они имеют очень специфическое применение, и если вы не знаете, что это такое, лучше не использовать его. От perlsub:

... Цель этой функции - в первую очередь позволить вам определять подпрограммы которые работают как встроенные функции

Просто удалите прототип из вашего объявления sub, и вы можете использовать любые аргументы, которые вам нравятся.

sub someFunction {
    my ( $oblig_param1, $oblig_param2, $option_param ) = @_;
    if (defined $option_param) {
        # do optional things
    }
    $option_param //= "default optional value";
    ....
} 

Ответ 3

Рекомендуется группировать параметры в $parameter hashref. Это особенно полезно, если необходимо предоставить несколько параметров (обязательный или необязательный).

Чтобы получить доступ к любому параметру, просто используйте $parameter->{oblig1} или $$parameter{option2}.

Передача hashrefs делает его особенно удобным при разработке, поэтому, когда возникает потребность в $oblig3, упорядочение аргументов изменяется ни на вызывающем, ни на самом sub. Сравните до и после:


# BEFORE $oblig3

--------------------------+-------------------------
# Caller                  | # Sub
--------------------------+-------------------------
someFunc( $oblig1,        | sub {
          $oblig2,        |   my ( $oblig1,
          $option1 );     |        $oblig2,
                          |        $option1 ) = @_;
                          | }
--------------------------+-------------------------

# AFTER $oblig3

--------------------------+-------------------------
# Caller                  | # Sub
--------------------------+-------------------------
someFunc( $oblig1,        | sub {
          $oblig2,        |   my ( $oblig1,
          $oblig3,        |        $oblig2,
          $option1 );     |        $oblig3,
                          |        $option1 ) = @_;
                          | }
--------------------------+-------------------------

Порядок аргументов изменяется как на вызывающем, так и на суб, поэтому порядок должен поддерживаться и соблюдаться.

Используя hashrefs, нет необходимости беспокоиться о порядке аргумента:

--------------------------+-------------------------
# Caller                  | # Sub
--------------------------+-------------------------
someFunc({ oblig1  => 1   | sub {
           oblig2  => 2   |   my ( $params ) = @_;
           option1 => 1   |   # No changes to    
           oblig3  => 7   |   # argument passing
         });              |  }    
                          | 
--------------------------+-------------------------

В зависимости от требований к дизайну подпрограммы могут использоваться следующие шаблоны аргументов подпрограммы:

  • my ( $mandatory_parameters, $optional_parameters ) = @_;

    Этот шаблон полезен, если его несколько. Красота этого подхода заключается в том, что $optional_parameters undefined, если он не передан, поэтому может быть выполнен случай по умолчанию if ! $optional_parameters;

    Обратите внимание, что обязательные параметры необходимо будет проверить впоследствии:

    for ( qw/ a b c / ) { 
        die "Missing '$_' parameter\n"
          unless exists $mandatory_parameters->{$_};
    }
    
  • my ( $parameters ) = @_;

    Полезно, если имеется несколько обязательных параметров или нет.

    Это также чрезвычайно эффективно, если параметры передаются для простого изменения поведения по умолчанию. Определив $default_parameters в объеме пакета, значения по умолчанию могут быть загружены с помощью следующего однострочного, если только параметр не был явно передан:

    $parameters = { %$default_parameters, %$parameters };