Значения аргумента по умолчанию в подпрограммах
Я не знаю, как установить параметры по умолчанию для подпрограмм. Вот что я рассмотрел:
sub hello {
print @_ || "Hello world";
}
Это прекрасно работает, если все, что вам нужно, это один аргумент. Как бы вы установили значения по умолчанию для нескольких аргументов?
Я собирался сделать это:
sub hello {
my $say = $_[0] || "Hello";
my $to = $_[1] || "World!";
print "$say $to";
}
Но это много работы... Должен быть более легкий путь; возможно, лучшая практика?
9 ответов
Я делаю это с именованными аргументами так:
sub hello {
my (%arg) = (
'foo' => 'default_foo',
'bar' => 'default_bar',
@_
);
}
Я считаю, что Params:: Validate поддерживает значения по умолчанию, но это больше проблем, чем я хотел бы принять.
Я обычно делаю что-то вроде:
sub hello {
my ($say,$to) = @_;
$say ||= "Hello";
$to ||= "World!";
print "$say $to\n";
}
Обратите внимание, что начиная с Perl 5.10, вы можете использовать//=
"оператор для проверки, если переменная определена, а не просто ненулевая. (Представьте себе вызов hello("0","friend")
который с использованием вышеупомянутого даст "Hello friend"
, что может быть не то, что вы хотели. С использованием //=
оператор это даст "0 friend"
).
Также посмотрите на 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 /
Если вы посмотрите документацию 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.
Мне нравится этот способ больше всего: начиная с 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
Поскольку механизм передачи аргументов подпрограммам в 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
,
В 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');
Лучший способ решить вашу проблему обсуждался в других ответах.
Одна вещь, которая поражает меня, это то, что вы заявляете, что:
sub hello { print @_ || "Hello world"; }
И это прекрасно работает, если все, что вам нужно, это один аргумент.
Вы действительно пробовали этот код? Он выведет количество аргументов или, если ничего не указано, Hello World
!
Причина этого заключается в том, что ||-оператор имеет приоритет и заставляет левую часть в скалярном контексте, тем самым уменьшая @_
на количество аргументов, которые вы предоставляете, а не сами аргументы!
взгляните на perlop для получения дополнительной информации об операторах в Perl.
НТН,
Павел
Для большего количества сахара, см. Также Method:: Signatures:
func add($this = 23, $that = 42) {
return $this + $that;
}