Мой $self = сдвиг в Perl; объяснение
Мне очень трудно понять пересечение OO Perl и my $self = shift;
Документация по этим отдельным элементам велика, но ни один из них, который я нашел, не касался того, как они работают вместе.
Я использую Moose для создания модулей с атрибутами, и, конечно, полезно ссылаться на атрибут модуля в указанном модуле. Мне снова и снова говорили использовать my $self = shift;
в рамках подпрограммы, чтобы назначать атрибуты модуля этой переменной. Это имеет смысл и работает, но когда я также передаю аргументы подпрограмме, этот процесс явно берет первый элемент массива @ARGV
и назначает его также $self
.
Может кто-нибудь предложить объяснение того, как я могу использовать shift, чтобы получить внутренний доступ к атрибутам модуля, а также передать аргументы в массиве @ARGV
?
Ответы
Ответ 1
Прежде всего, подпрограмма не передается массивом @ARGV
. Скорее все параметры, переданные подпрограмме, сглаживаются в один список, представленный @_
внутри подпрограммы. Массив @ARGV доступен на верхнем уровне вашего script, содержащего аргументы командной строки, переданные вам script.
Теперь, в Perl, когда вы вызываете метод объекта, объект неявно передается в качестве параметра для метода.
Если вы игнорируете наследование,
$obj->doCoolStuff($a, $b);
эквивалентно
doCoolStuff($obj, $a, $b);
Это означает, что содержимое @_
в методе doCoolStuff
будет: @_ = ($obj, $a, $b);
Теперь встроенная функция shift
без каких-либо параметров сдвигает элемент из переменной массива по умолчанию @_
. В этом случае это будет $obj
.
Итак, когда вы делаете $self = shift
, вы эффективно говорите $self = $obj
.
Я также надеюсь, что это объясняет, как передать другие параметры методу с помощью обозначения ->
. Продолжая приведенный выше пример, это будет выглядеть так:
sub doCoolStuff {
# Remember @_ = ($obj, $a, $b)
my $self = shift;
my ($a, $b) = @_;
Кроме того, в то время как Moose
является отличным объектным уровнем для Perl, он не отменяет требования, необходимые для инициализации $self
самостоятельно в каждом методе. Всегда помните об этом. Хотя язык, подобный С++ и Java, инициализирует ссылку на объект this
неявно, в Perl вам нужно сделать это явно для каждого метода, который вы пишете.
Ответ 2
В коде верхнего уровня shift()
сокращен для shift(@ARGV)
. @ARGV
содержит аргументы командной строки.
В подстроке shift()
сокращен для shift(@_)
. @_
содержит вспомогательные аргументы.
Итак, my $self = shift;
захватывает первый аргумент. При вызове метода в качестве первого параметра передается invocant (то, что осталось от ->
). Другими словами,
$o->method(@a)
похож на
my $sub = $o->can('method');
$sub->($o, @a);
В этом примере my $self = shift;
назначит $o
$self
.
Ответ 3
Если вы вызываете:
$myinstance->myMethod("my_parameter");
- это то же самое, что и делать:
myMethod($myinstance, "my_parameter");
но если вы выполните:
myMethod("my_parameter");
будет передан только "my_parameter".
ТОГДА, если внутри myMethod вы всегда делаете:
$self = shift @_;
$self будет ссылкой на объект при вызове myMethod id из контекста объекта
но будет "my_parameter" при вызове из другого метода внутри процедурным способом.
Помните об этом;