Выражение perl "or" и подпрограмма "isa"
Я столкнулся с этим кодом, но я не понимаю его.
$type->isa('UNIVERSAL')
or eval "require $type"
or croak $@;
Я ссылался на
perldoc
и я знаю, что подпрограммаisa()
проверяет,$type
был благословлен на пакетUNIVERSAL
, Но на самом деле все классы Perl являются подклассамиUNIVERSAL
, право?Я запутался в двух
or
термины. Что они имеют в виду?
4 ответа
Прикованный or
мелодия
в Perl or
оператор работает так же, как ||
но имеет очень низкий приоритет, то есть насколько "тесно" он привязывается к окружающему коду. Логическое или в Perl короткое замыкание, то есть оценка останавливается, как только операнд оценивает значение true.
Распространенная идиома в Perl использует короткое замыкание для управления потоком, часто связанное с обработкой ошибок, как в
open my $fh, "<", $path or die "$0: open: $!";
В случае успеха, open
возвращает истинное значение. Результат or
истина, когда хотя бы один из ее операндов верен, поэтому при успешном open
Perl не die
потому что правый операнд or
не оценивается.
Цепи or
операторы могут быть произвольно расширены. Это полезно для определения значений по умолчанию. В простом случае это выглядит так
my $name = shift or "Bruce";
Если у вас есть несколько резервных вариантов, разместите их в том порядке, в котором вы хотите их попробовать.
my $name = shift or given_name $family_name or "Bruce";
Первый случай, чтобы преуспеть, побеждает.
Код
$type->isa('UNIVERSAL')
or eval "require $type"
or croak $@;
такая цепь Оценка проводится в следующем порядке:
$type->isa('UNIVERSAL')
eval "require $type"
croak $@
Если $type
это имя пакета, который уже существует, тогда шаги 2 и 3 игнорируются.
Достижение шага 2 означает $type
не загружен, поэтому теперь код пытается require
Это. Если require
успешно, шаг 3 игнорируется.
Достижение шага 3 означает, что пакет не существует и его невозможно загрузить. В этом случае, croak
выводит причину сбоя и выходит из программы.
Был ли загружен определенный модуль?
Когда вызывается как метод, isa
имеет три формы:
$obj->isa( TYPE )
CLASS->isa( TYPE )
eval { VAL->isa( TYPE ) }
Третий - это универсальный универсальный подход, который здесь не актуален. Первый - это то, что вы описали в своем вопросе.
Второе задокументировано как
При использовании в качестве метода класса (
CLASS->isa( TYPE )
), иногда называемый статическим методом),isa
возвращает true, еслиCLASS наследует (или является самим собой) имя пакета TYPE или наследует от пакета TYPE.
Линия как раз передor
цепь в::_factory
из SOAP:: WSDL:: XSD:: TypeLib:: ComplexType, есть
my $type = $CLASSES_OF{ $class }->{ $name }
or croak "No class given for $name";
Здесь значение$type
это строка, такisa
проверяет, является ли класс с именем $type
наследует от универсального. Как вы отметили в своем вопросе, все классы наследуются от UNIVERSAL.
Так, что происходит? Еслиisa
не удается, код вызываетrequire
так что намерение isa
необходимо проверить, был ли загружен данный класс.
Существует ли определенный пакет?
Помните, что классы Perl и пакеты Perl тесно связаны. Чтобы класс существовал, пакет с таким же именем должен существовать. Обнаружение неразрушающего, существует ли пакет, оказывается хитрым. Зондирование тайника%Foo::Bar::Baz::Quux::
непосредственно автовивитирует. Perl хранит тайники в иерархическом порядке, так что вам придется записываться как
sub package_exists {
my($pkg) = @_;
$pkg =~ s/::$//;
my @parts = split /::/, $pkg;
my $stash = $main::{"main::"};
while (@parts) {
my $subpkg = shift(@parts) . "::";
return unless exists $stash->{$subpkg};
$stash = $stash->{$subpkg};
}
$stash;
}
Успешныйrequire
изменяет специальный хеш с именем % INC. Я не уверен, почему код не проверяет %INC
, Возможно, некоторые типы загружаются вне механизма require, или, возможно, автор был доволен этим восхитительным маленьким хакером.
Рассмотрим источникsv_derived_from
, который реализуетisa
,
bool
Perl_sv_derived_from_pvn(pTHX_ SV *sv,
const char *const name, const STRLEN len,
U32 flags)
{
dVAR;
HV *stash;
PERL_ARGS_ASSERT_SV_DERIVED_FROM_PVN;
SvGETMAGIC(sv);
if (SvROK(sv)) {
const char *type;
sv = SvRV(sv);
type = sv_reftype(sv,0);
if (type && strEQ(type,name))
return TRUE;
stash = SvOBJECT(sv) ? SvSTASH(sv) : NULL;
}
else {
stash = gv_stashsv(sv, 0);
if (!stash)
stash = gv_stashpvs("UNIVERSAL", 0);
}
return stash ? isa_lookup(stash, name, len, flags) : FALSE;
}
Имейте в виду, что мы вызываем этот код с
"SomeClass"->isa("UNIVERSAL")
такsv
содержит строку"SomeClass"
,SvROK
проверяет,sv
является ссылкой, которой не является строка, поэтому мы всегда в else
ветка.
В конце концов, значение stash
всегда будет не NULL
: указывает на таблицу символов пакета, если он был загружен, или UNIVERSAL в противном случае. Поиск успешен для загруженных пакетов и завершается неудачно в противном случае. Попробуй сам:
$ perl -le 'print "strict" -> isa ("УНИВЕРСАЛЬНЫЙ")? "загружен": "не загружен"' не загружен$ perl -Mstrict -le 'print "strict"->isa("УНИВЕРСАЛЬНЫЙ")? "загружен": "не загружен"' нагруженный
isa
используется здесь, чтобы проверить, был ли данный пакет импортирован сrequire
или жеuse
,Package->isa('UNIVERSAL')
вернет true, если packcagePackage
существует, иначе ложь.or
используется вshort circuit
вместимость. В выраженииa or b
,b
не будет оцениваться, еслиa
имеет истинное значение. Это не имеет значения, если термины являются переменными, но если они являются вызовами подпрограммы, которые имеют побочные эффекты, то это становится альтернативойif
заявление.Соответствующее утверждение эквивалентно этому коду
unless ($type->isa('UNIVERSAL')) { unless (eval "require $type") { croak $@; } }
Общий эффект состоит в том, чтобы проверить, является ли модуль, указанный переменной
$type
был импортирован. Если нет тоrequire
используется для его импорта, иcroak
вызывается, если это не удается.
Вопрос 1
UNIVERSAL - базовый класс для всех классов Perl.
вопрос 2
or
в Perl оператор низкого приоритета, означающий
A or B
верно, еслиA
верно, или еслиB
Истина, то есть, если любое из двух условий верно.- низкий приоритет означает, что выражение
A
выше оценивается доor
, при условии, чтоA
приоритет операторов выше чемor
, Что может быть в случаеor
(В отличие от||
) имеет самый низкий приоритет в Perl.
В Perl дано выражение
A or B or C;
B
обрабатывается (оценивается) только если A
ложно, иC
обрабатывается (оценивается) только если B
ложно
Практически в вашем случае, если $type->isa('UNIVERSAL')
Это правда, Perl останавливается здесь и считает все выражение истинным. Если ложь, он будет оценивать eval "require $type"
: если true, то все выражение истинно, если false, оно, наконец, оценивает croak $@
,
Это быстрый способ сделать
if ( ! $type->isa('UNIVERSAL')) {
if ( ! eval "require $type") {
croak $@;
}
}
С or
, perl выполнит предложение правой стороны, только если выполнение слева возвращает не ложное значение