Значения аргумента по умолчанию в подпрограммах - PullRequest
13 голосов
/ 23 августа 2010

Я не знаю, как установить аргументы по умолчанию для подпрограмм.Вот что я рассмотрел:

sub hello {
  print @_ || "Hello world";
}

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

Я собирался сделать это:

sub hello {
  my $say = $_[0] || "Hello";
  my $to  = $_[1] || "World!";
  print "$say $to";
}

Но это много работы ... Должен быть более легкий путь;возможно, лучшая практика?

Ответы [ 9 ]

14 голосов
/ 23 августа 2010

Я делаю это с именованными аргументами, например, так:

sub hello {
    my (%arg) = (
        'foo' => 'default_foo',
        'bar' => 'default_bar',
        @_
    );

}

Я считаю, Params :: Validate поддерживает значения по умолчанию, но это больше проблем, чем мне нравится принимать.

11 голосов
/ 23 августа 2010

Я обычно делаю что-то вроде:

sub hello {
    my ($say,$to) = @_;
    $say ||= "Hello";
    $to ||= "World!";
    print "$say $to\n";
}

Обратите внимание, что начиная с perl 5.10, вы можете использовать оператор "//=", чтобы проверить, определена ли переменная, а не просто ненулевая.(Представьте, что вызов hello("0","friend"), который с использованием вышеупомянутого, даст "Hello friend", что может быть не тем, что вы хотели. Используя оператор //=, вы получите "0 friend").

5 голосов
/ 23 августа 2010

Также взгляните на Method::Signatures. При этом используется Devel::Declare для предоставления дополнительного (необходимого!) Сахара с ключевыми словами method и func.

Ниже приведен пример использования func:

use Method::Signatures;

func hello ($say='Hello', $to='World!') {
    say "$say $to";
}

hello( 'Hello', 'you!' );    # => "Hello you!"
hello( 'Yo' );               # => "Yo World!"
hello();                     # => "Hello World!"

/ I3az /

4 голосов
/ 23 августа 2010

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

Более чистый способ сделатьэто с помощью именованных аргументов.Perl не поддерживает именованные аргументы как таковые , но вы можете эмулировать их с помощью хэшей:

use 5.010;  # for //

sub hello {
    my %arg = @_;
    my $say = delete $arg{say} // 'Hello';
    my $to  = delete $arg{to}  // 'World!';
    print "$say $to\n";
}

hello(say => 'Hi', to => 'everyone');  # Hi everyone
hello(say => 'Hi');                    # Hi world!
hello(to  => 'neighbor Bob');          # Hello neighbor Bob
hello();                               # Hello world!

Примечание: определенный оператор или // был добавлен в Perl v5.10,Это более надежно, чем использование логического или (||), так как оно не будет иметь значения по умолчанию для логически ложных значений '' и 0.

2 голосов
/ 23 августа 2010

Если вы видите документацию Perl Best Practices : Аргумент по умолчанию Значения от Дамиана Конвея , тогда вы найдете несколько важных моментов, таких как:

  • Разрешить любые значения аргументов по умолчанию , как только @_ будет распакован.
  • Предполагается, что если у вас есть много значений по умолчанию для установки, то самым чистым способом будет выделение значений по умолчанию в таблицы, т. Е. Хэш , а затем преинициализация хеша аргумента с этой таблицей.

Пример:

#!/usr/bin/perl
  use strict;
  use warning;
  my %myhash = (say => "Hello", to => "Stack Overflow");
  sub hello {
   my ($say, $to) = @_;
   $say =  $say ? $say : $myhash{say};
   $to =  $to ? $to : $myhash{to};
   print "$say $to\n";
  }
  hello('Perl');      # output :Perl Stack Overflow
  hello('','SO');     # output :Hello SO
  hello('Perl','SO'); # output :Perl SO
  hello();            # output :Hello Stack Overflow

Для более подробной информации и полного примера см. Perl Best Practices .

2 голосов
/ 23 августа 2010

В CPAN есть модуль Attribute :: Default . Возможно, чище, чем это, и позволяет избежать пары сложностей (например, что, если вы хотите передать false своей подпрограмме?).

Я также видел, как люди используют my $var = exists @_[0] ? shift : "Default_Value";, но в документации Perl отмечается, что вызов exists для массивов устарел , поэтому я бы не стал его рекомендовать.

Фрагмент Attribute::Default со страницы документа:

  sub vitals : Default({age => 14, sex => 'male'}) {
     my %vitals = @_;
     print "I'm $vitals{'sex'}, $vitals{'age'} years old, and am from $vitals{'location'}\n";
  }

   # Prints "I'm male, 14 years old, and am from Schenectady"
   vitals(location => 'Schenectady');
1 голос
/ 23 августа 2010

Лучший способ решения вашей проблемы обсуждался в других ответах.Однако меня поражает одна вещь: вы заявляете:

sub hello {
   print @_ || "Hello world";
}

И это прекрасно работает, если все, что вам нужно, это один аргумент.

Вы действительно пробовали этот код?Он выведет количество аргументов или, если ничего не указано, Hello World!Причина этого в том, что || -оператор имеет приоритет и задает левую часть в скалярном контексте, уменьшая таким образом @_ до количества аргументов, которые вы предоставляете, а не самих аргументов!взгляните на perlop для получения дополнительной информации об операторах в Perl.НТН,Пол

0 голосов
/ 15 октября 2018

Мне больше нравится этот способ: начиная с Perl 5.10, вы можете использовать //, чтобы проверить, определена ли переменная или нет, и предоставить альтернативное значение, если это не так. Итак, простой пример:

my $ DEFAULT_VALUE = 42;

sub f {
    my ($p1, $p2) = @_;
    $p1 //= 'DEFAULT';
    $p2 // = $DEFAULT_VALUE;
}

Другой вариант - использовать инструкцию shift для получения параметров из @_:

sub f {
    my $p1 = shift // 'DEFAULT';
}

Источник: https://perlmaven.com/how-to-set-default-values-in-perl

0 голосов
/ 23 августа 2010

Подробнее о сахаре см. Также Метод :: Подписи :

func add($this = 23, $that = 42) {
    return $this + $that;
}
...