Ответ 1
Это связано с синтаксисом косвенного объекта и является более сложным вариантом этого примера.
"косвенная запись объекта" разрешает код
PackageName->method(@args);
записывается как
method PackageName @args;
Поэтому слова "попробуй" и "поймай" не имеют значения. Интересным моментом здесь является более сложный и расширенный синтаксис, состоящий из двух частей, каждая в этой записи косвенного объекта.
На самом деле рассматриваемый код имеет форму method BLOCK LIST
, но он также идет по косвенному синтаксису объекта в (do BLOCK)->method(LIST)
, где do BLOCK
необходимо создать имя пакета или благословенную (объектную) ссылку для значимого вызова метода. Это видно из вывода Deparse
.
Использование B :: Deparse серверной части компилятора (через O модуль) для этого кода
use strict;
use warnings;
use feature 'say';
try { call_a( 'x' ) }
catch {
die "ACTUALLY die";
#say "NO DONT die";
};
sub call_a {
die "Yes it dies";
#say "no die";
}
поскольку perl -MO=Deparse script.pl
должен показывать очень близкое приближение к тому, что работает:
use warnings; use strict; use feature 'say'; try { call_a('x') } do { die 'ACTUALLY die' }->catch; sub call_a { use warnings; use strict; use feature 'say'; die 'Yes it dies'; } undef_sub.pl syntax OK
Синтаксис вложенного косвенного объекта явно слишком велик для Deparse
, который все еще оставляет форму method BLOCK LIST
в выходных данных. Эквивалентный код можно записать как
(do { call_a('x') })->try( (do { die("ACTUALLY die") })->catch() );
что в этом случае проще
call_a('x')->try( die("ACTUALLY die")->catch() );
Таким образом, исходный код интерпретируется как действительный синтаксис (!), и это содержимое блока после try
(call_a('x')
), которое запускается первым - так что программа умирает и никогда не добивается " метод "try
.
Будет интереснее, если мы изменим пример на
use strict;
use warnings;
use feature 'say';
try { call_a( 'x' ) }
catch {
#die "ACTUALLY die";
say "NO DONT die";
};
sub call_a {
#die "Yes it dies";
say "no die";
}
без die
-ing нигде. Запустите его с -MO=Deparse
, чтобы увидеть
use warnings;
use strict;
use feature 'say';
try {
call_a('x')
} (catch {
say 'NO DONT die'
} );
sub call_a {
use warnings;
use strict;
use feature 'say';
say 'no die';
}
undef_sub.pl syntax OK
который теперь имеет прямой синтаксис method {} args
(с самим args
, показанным Deparse
также в косвенной записи объекта).
Эквивалентный код
call_a('x')->try( say("NO DONT die")->catch() );
где сначала идет call_a()
, а после его возврата затем выполняется код для списка аргументов в вызове метода try
. Мы не сталкиваемся с die
, и фактический пробег выглядит как
no die NO DONT die Can't call method "catch" without a package or object reference at ...
Итак, теперь проблема с методом "catch" действительно возникает.
Спасибо икегами за комментарии
Если блок выше должен был вернуть имя пакета (или ссылку на объект), у которого есть метод catch
, то в конце концов также будет предпринята попытка try
use strict;
use warnings;
use feature 'say';
BEGIN {
package Catch;
sub catch { say "In ", (caller(0))[3] };
$INC{"Catch.pm"} = 1;
};
use Catch;
try { call_a( 'x' ) }
catch {
say "NO DONT die";
"Catch";
};
sub call_a { say "no die" }
Теперь у нас есть эквивалент
call_a('x')->try( do { say("NO DONT die"); 'Catch' }->catch() );
с выводом
no die NO DONT die In Catch::catch Can't call method "try" without a package or object reference at undef_sub.pl line 14.