ключевое слово конструктора perl 'new'

Я новичок в Perl и в настоящее время изучаю Perl объектно-ориентированный и наткнулся на написание конструктора. Похоже, при использовании new на имя подпрограммы первым параметром будет имя пакета.

должен ли конструктор использовать ключевое слово new? Или это потому, что когда мы называем new подпрограмма с использованием packagename, то первым параметром, который будет передан, будет имя пакета?

packagename->new;

и когда подпрограмма имеет другое имя это будет первым параметром будет ссылка на объект? Или это потому, что когда подпрограмма вызывается через ссылку на объект, так что первый параметр, который будет передан, будет ссылкой на объект?

$objRef->subroutine;

2 ответов


это не первый параметр new, но синтаксис косвенного объекта,

perl -MO=Deparse -e 'my $o = new X 1, 2'

который анализируется как

my $o = 'X'->new(1, 2);

С perldoc,

Perl поддерживает другой синтаксис вызова метода, называемый нотацией "косвенный объект". Этот синтаксис называется "косвенным", поскольку метод предшествует объекту, на который он вызывается.

это, как говорится, new - это не какое-то зарезервированное слово для конструктора вызов, но имя самого метода / конструктора, которое в perl не применяется (т. е. DBI и connect конструктор)


NB: все приведенные ниже примеры упрощены для учебных целей.

Методы

Да, вы правы. Первый аргумент для вашего , если вызывается как метод, будет то, против чего вы его вызвали.

есть два "аромата" вызова метода, но результат одинаков в любом случае. Один вкус полагается на оператор, двоичный -> оператора. Другой вкус опирается на упорядочение аргументов, путь bitransitive глаголы работа на английском языке. Большинство людей используют дательный / bitransitive стиль только со встроенными-и возможно с конструкторами, но редко что-нибудь еще.

при большинстве (но не совсем всех) обстоятельств эти первые два эквивалентны:

1. Дательный вызов методов

это позиционный, тот, который использует порядок слов, чтобы определить, что происходит.

use Some::Package;
my $obj1 = new Some::Package NAME => "fred"; 

обратите внимание, что мы не используем стрелку метода: нет -> как написано. Это то, что сам Perl использует со многими своими собственными функциями, такими как

 printf STDERR "%-20s: %5d\n", $name, $number;

который почти каждый предпочитает эквиваленту:

 STDERR->printf("%-20s: %5d\n", $name, $number);

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

2. стрелка вызов методов

вызов стрелки по большей части яснее и чище, и менее вероятно, что вы запутались в сорняках Perl разбора странностей. Заметьте, я сказал меньше вероятность и не сказать, что он был свободен от всех недоработок. Но давайте просто притворимся так для целей этого ответа.

use Some::Package;
my $obj2 = Some::Package->new(NAME => "fred");

во время выполнения, исключая любые причудливые странности или наследование имеет значение, фактический вызов функции будет

 Some::Package::new("Some::Package", "NAME", "fred");

например, если вы были в отладчике Perl и сделали дамп стека, у него было бы что-то вроде предыдущей строки в цепочке вызовов.

после вызова метода всегда префиксов списка параметр с invocant, все функции, которые будут вызываться как методы должны учитывать, что "лишние" первый аргумент. Это очень легко сделать:

package Some::Package;
sub new {
   my($classname, @arguments) = @_;
   my $obj = { @arguments };
   bless $obj, $classname;
   return $obj;
}

это просто чрезвычайно упрощенный пример новых наиболее частых способов вызова конструкторов и того, что происходит внутри. В реальном производственном коде конструктор будет гораздо более осторожным.

методы и косвенного

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

print 3.14;    # print a number directly

$var = 3.14;   # or indirectly
print $var;

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

3. Вызов стрелка с Indirected метод название:

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

use Some::Package;
my $action = (rand(2) < 1) ? "new" : "old";
my $obj    = Some::Package->$action(NAME => "fido");

здесь само имя метода неизвестно до времени выполнения.

4. Вызов стрелка с Indirected класс название:

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

my $class = (rand(2) < 1) 
              ? "Fancy::Class" 
              : "Simple::Class";
my $obj3 = $class->new(NAME => "fred");

теперь мы случайным образом выбираем тот или иной класс.

вы также можете использовать дательный вызов таким образом:

my $obj3 = new $class NAME => "fred";

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

my $fh = ($error_count == 0) ? *STDOUT : *STDERR;
printf $fh "Error count: %d.\n", $error_count;

это потому, что попытка использовать выражение в слоте dative не будет работать вообще без блока вокруг него; в противном случае это может быть только простая скалярная переменная, даже не один элемент из массива или хэша.

printf { ($error_count == 0) ? *STDOUT : *STDERR } "Error count: %d.\n", $error_count;

или проще:

print { $fh{$filename} } "Some data.\n";

это чертовски некрасиво.

пусть призывающий остерегайтесь

обратите внимание, что это не работает совершенно. Литерал в слоте объекта dative работает иначе, чем переменная. Например, с литерал работы:

print STDERR;

означает

print STDERR $_;

но если вы используете косвенные filehandles, вот так:

print $fh;

это на самом деле означает

print STDOUT $fh;

что вряд ли означает то, что вы хотели, что, вероятно, было это:

print $fh $_;

ака

$fh->print($_);

Дополнительные Функции: Методы Двойной Природы

дело в методе вызова стрелки -> является ли он агностическим о том, является ли его левый операнд строкой, представляющей имя класса, или благословенной ссылкой, представляющей экземпляр объекта.

конечно, ничто формально не требует, чтобы $class содержит имя пакета. Это может быть, и если это так, то до сам метод делать правильные вещи.

use Some::Class;

my $class = "Some::Class";
my $obj   = $class->new(NAME => "Orlando"); 

my $invocant = (rand(2) < 1) ? $class : $obj;
$invocant->any_debug(1);

это требует довольно фантазии any_debug метод, который делает что-то другое в зависимости от того, был ли его призывающий благословлен или нет:

package Some::Class;
use Scalar::Util qw(blessed);

sub new {
   my($classname, @arguments) = @_; 
   my $obj = { @arguments };
   bless $obj, $classname;
   return $obj;
}   

sub any_debug {
    my($invocant, $value) = @_;
    if (blessed($invocant)) {
        $invocant->obj_debug($value);
    } else {
        $invocant->class_debug($value);
    }
}

sub obj_debug {
    my($self, $value) = @_;
    $self->{DEBUG} = $value;
}

my $Global_Debug;
sub class_debug {
    my($classname, $value) = @_;
    $Global_Debug = $value;
}