На Perl аргументов подпрограммы
Я недавно читал о Perl и немного озадачен тем, как Perl обрабатывает аргументы, переданные подпрограммам.
в языке, таком как Python, Java или PHP, определение функции принимает форму (в псевдокоде):
function myFunc(arg1, arg2) {
// Do something with arg1 and arg2 here
}
но в Perl это просто:
sub mySub {
# @_ holds all arguments passed
}
и как я понимаю, это единственный способ сделать это.
что если я хочу ограничить абоненту пройти только 2 споры?
разве это не просто Perl не позволяет ничего, кроме аргументов с переменным числом на других языках (например, Python, C и т. д.)?
не станет ли это проблемой в какой-то момент?
-
как насчет проверки всех аргументов по умолчанию на других языках? Нужно ли делать это явно в Perl? Например,
sub a_sub { if (@_ == 2) { # Continue function } else { return false } }
7 ответов
вы опасаетесь среды Perl, потому что она сильно отличается от языков, с которыми вы сталкивались раньше.
люди, которые верят в сильные прототипы типов и функций, не согласятся здесь, но я считаю, что такие ограничения редко полезны. Имеет C действительно поймал вас, передавая неправильное количество параметров функции достаточно часто, чтобы быть полезным?
наиболее распространено в современном Perl копировать содержимое @_
к списку лексических скалярных переменных, поэтому вы часто увидите подпрограммы, начинающиеся с
sub mysub {
my ($p1, $p2) = @_;
... etc.
}
таким образом, все передаваемые параметры будут доступны в виде элементов @_
($_[0]
, $_[1]
etc.), а ожидается они называются и появляются в $p1
и $p2
(хотя я надеюсь, вы понимаете, что эти имена должны быть выбраны соответствующим образом).
в частном случае, когда подпрограмма является метод первый параметр-это специальные. На других языках это self
или this
, но в Perl это просто первый параметр @_
и вы можете называть это, как вам нравится. При таких обстоятельствах вы бы увидели
sub method {
my $self = shift;
my ($p1, $p2) = @_;
... etc.
}
так что объект контекста (или имя класса, если это метод класса) извлекается в $self
(имя, принятое по соглашению), а остальные параметры остаются в @_
для прямого доступа или, как правило,, скопировано в локальные скалярные переменные как $p1
, $p2
etc.
чаще всего жалоба заключается в том, что нет проверки типа, поэтому я могу передать любой скаляр, который мне нравится, как параметр подпрограммы. Пока use strict
и use warnings
находятся в контексте, даже это обычно просто отлаживать, просто потому, что операции, которые подпрограмма может выполнять на одной форме скаляра, обычно незаконны на другой.
хотя первоначально это было больше связано с инкапсуляцией с что касается объектно-ориентированного Perl, эта цитата из Ларри Уолла очень актуальна
у Perl нет увлечения принудительной приватностью. Он предпочел бы, чтобы вы остались вне его гостиной, потому что вы не были приглашены, а не потому, что у него есть дробовик
C был разработан и реализован в те дни, когда он был майор повышение эффективности, если вы можете получить неисправную программу для сбоя во время компиляции, а не во время выполнения. Что изменилось сейчас, хотя аналогичная ситуация возникла с клиентским JavaScript, где это на самом деле б полезно знать, что код неверен, прежде чем получать данные из интернета, с которым он должен иметь дело. К сожалению, проверка параметров JavaScript теперь свободнее, чем должна быть.
обновление
для тех, кто сомневается в полезности Perl для учебных целей, я полагаю, что это именно так Механизмы Perl настолько просты и непосредственны, что они идеал для таких целей.
при вызове подпрограммы Perl все параметры в вызове являются псевдоним на
@_
. Вы можете использовать их напрямую, чтобы повлиять на фактические параметры, или скопировать их, чтобы предотвратить внешние действияесли вы вызываете подпрограмму Perl как метод затем вызывающий объект или класс как первый параметр. Опять же, подпрограмма (метод) может делать то, что ей нравится с
@_
Perl не управляет обработкой аргументов для вас. Вместо этого он обеспечивает минимальную, гибкую абстракцию и позволяет писать код, который соответствует вашим потребностям.
Проходим По Ссылке
по умолчанию Perl вставляет псевдоним для каждого аргумента в @_
. Это реализует основные, проходим по ссылке семантика.
my $num = 1;
foo($num);
print "$num\n"; # prints 2.
sub foo { $_[0]++ }
Pass по ссылке быстро, но имеет риск утечки изменений в данные параметров.
Проходим Мимо Копия
если вы хотите пройти мимо copy семантика, вам нужно сделать копии самостоятельно. В сообществе Perl распространены два основных подхода к обработке списков позиционных параметров:
sub shifty {
my $foo = shift;
}
sub listy {
my ($foo) = @_;
}
на моем месте работы мы делаем версию listy:
sub fancy_listy {
my ($positional, $args, @bad) = @_;
die "Extra args" if @bad;
}
Именованные Параметры
Другой распространенной практикой является использование именованные параметры:
sub named_params {
my %opt = @_;
}
некоторые люди довольны только вышесказанным. Я предпочитаю более подробный подход:
sub named_params {
my %opt = @_;
my $named = delete $opt{named} // "default value";
my $param = delete $opt{param}
or croak "Missing required 'param'";
croak "Unknown params:", join ", ", keys %opt
if %opt;
# do stuff
}
это распаковывает именованные параметры в переменные, разрешает пространство для базовой проверки и значений по умолчанию и обеспечивает, чтобы никакие дополнительные неизвестные аргументы не передавались.
На Прототипах Perl
"прототипы" Perl являются не прообразы в обычном смысле. Они предоставляют только подсказки компилятора, которые позволяют пропустить скобки при вызовах функций. Единственное разумное использование-имитировать поведение встроенных функций. Вы можете легко победить проверку аргументов прототипа. В общем, НЕ ИСПОЛЬЗОВАТЬ ПРОТОТИПЫ. Используйте их с осторожностью, чтобы использовать перегрузку оператора-т. е. экономно и только для улучшения читаемости.
по какой-то причине Perl любит списки и не любит статическую типизацию. The @_
массив фактически открывает большую гибкость, потому что аргументы подпрограммы передаются по ссылке, а не по стоимости. Например, это позволяет нам делать-аргументы:
my $x = 40;
add_to($x, 2);
print "$x\n"; # 42
sub add_to { $_[0] += $_[1] }
... но это скорее исторический Хак производительности. Обычно аргументы "объявляются" назначением списка:
sub some_sub {
my ($foo, $bar) = @_;
# ^-- this assignment performs a copy
...
}
это делает семантику этого sub call-by-value, что обычно более желательно. Да, неиспользуемые аргументы просто забываются, и слишком мало аргументов не вызывают автоматической ошибки – переменные просто содержат undef
. Вы можете добавить произвольную проверку, например, проверив размер @_
.
существуют планы наконец сделать именованные параметры доступными в будущем, которые будут выглядеть как
sub some_sub($foo, $bar) { ... }
вы можете иметь следующий синтаксис если вы установите signatures
. Но есть кое-что еще лучше: я могу настоятельно рекомендовать Function::Parameters
, который позволяет синтаксис, как
fun some_sub($foo, $bar = "default value") { ... }
method some_method($foo, $bar, :$named_parameter, :$named_with_default = 42) {
# $self is autodeclared in methods
}
это также поддерживает проверки экспериментального типа.
расширения парсера FTW!
Если вы действительно хотите ввести более строгие проверки параметров в Perl, вы можете посмотреть что-то вроде Params:: Validate.
У Perl есть прототипирование возможность для заполнителей параметров, которые вы привыкли видеть, но это часто не нужно.
sub foo($){
say shift;
};
foo(); # Error: Not enough arguments for main::foo
foo('bar'); # executes correctly
и если вы сделали sub foo($$){...}
для этого потребуется 2 необязательных аргумента (например,foo('bar','baz')
)
Вы можете просто использовать:
my ($arg1, $arg2) = @_;
чтобы явно ограничить количество аргументов, которые можно использовать:
my $number =2;
die "Too many arguments" if @_ > $number;
Если Вы читаете о perl в последнее время, пожалуйста, прочитайте последние perl. Вы можете прочитать В Современном Языке Perl книги бесплатно, а также: бесплатная онлайн современная книга Perl
вот несколько примеров из этой книги о подписи функции:
sub greet_one($name = 'Bruce') {
say "Hello, $name!";
}
sub greet_all($leader, @everyone) {
say "Hello, $leader!";
say "Hi also, $_." for @everyone;
}
sub make_nested_hash($name, %pairs) {
return { $name => \%pairs };
}