Почему Perl позволяет вызывать coderefs для небезопасных структур данных? - PullRequest
8 голосов
/ 14 ноября 2011

При выполнении оператора $obj->method();, perldiag говорит, что Perl должен знать, к какому пакету принадлежит метод. Вот почему его нужно благословить:

Невозможно вызвать метод "% s" для необязательной ссылки

(F) Вызов метода должен знать, в каком пакете он должен выполняться. Это обычно узнает об этом из ссылки на объект, которую вы предоставляете, но Вы не указали ссылку на объект в этом случае. Ссылка не ссылка на объект, пока он не будет благословлен. Увидеть perlobj.

Из-за этого невозможно сделать следующее:

my $data = [
             [ 1, 2, 3 ],
             [ 4, 5, 6 ],
           ];

$data->process( @params );  # Can't call method "process" on unblessed reference

Тогда почему он работает с coderef?:

my $process = \&process;    # Same method as before
$data->$process( @params ); # Works fine now

Ответы [ 3 ]

22 голосов
/ 14 ноября 2011
$variable->method(@args)

просто вызывает

method($variable, @args)

Но в каком пакете Perl должен найти подпрограмму method? Если $variable является благословенной ссылкой, Perl будет искать подпрограмму в пакете, возвращаемом ref $variable. Если $variable является строкой и именем пакета, Perl будет искать подпрограмму в этом имени пакета.

Во втором примере, когда вы объявляете

$process = \&process

вы дали Perl ссылку на код, который хотите вызвать, поэтому Perl знает, как принять вызов

$variable->$process(@args)

и вызвать

$process->($variable, @args)

или

&process($variable, @args)

Только когда $variable является ссылкой unblessed , а имя метода не может быть преобразовано в ссылку на код, Perl не может понять, что делать, и вводит команды

10 голосов
/ 14 ноября 2011

Когда Perl видит $x->$y, он компилирует его в нечто вроде:

if (reftype $y eq 'CODE') {
    $y->($x)
}
else {
    if (my $code_ref = eval {$x->can($y)}) {
        $code_ref->($x)
    }
    else {
       die "error"
    }
}

Если $y оказывается голым словом, первая проверка всегда ложна, а затем выполняется блок elseнормальный вызов метода.

6 голосов
/ 14 ноября 2011

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

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

...