Выражение perl "or" и подпрограмма "isa"

Я столкнулся с этим кодом, но я не понимаю его.

$type->isa('UNIVERSAL')
  or eval "require $type"
    or croak $@;
  1. Я ссылался на perldoc и я знаю, что подпрограмма isa() проверяет, $type был благословлен на пакет UNIVERSAL, Но на самом деле все классы Perl являются подклассами UNIVERSAL, право?

  2. Я запутался в двух or термины. Что они имеют в виду?

4 ответа

Решение

Прикованный or мелодия

в Perl or оператор работает так же, как || но имеет очень низкий приоритет, то есть насколько "тесно" он привязывается к окружающему коду. Логическое или в Perl короткое замыкание, то есть оценка останавливается, как только операнд оценивает значение true.

Распространенная идиома в Perl использует короткое замыкание для управления потоком, часто связанное с обработкой ошибок, как в

open my $fh, "<", $path or die "$0: open: $!";

В случае успеха, open возвращает истинное значение. Результат or истина, когда хотя бы один из ее операндов верен, поэтому при успешном openPerl не 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 $@;

такая цепь Оценка проводится в следующем порядке:

  1. $type->isa('UNIVERSAL')
  2. eval "require $type"
  3. 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("УНИВЕРСАЛЬНЫЙ")? "загружен": "не загружен"'
нагруженный
  1. isa используется здесь, чтобы проверить, был ли данный пакет импортирован с require или же use, Package->isa('UNIVERSAL') вернет true, если packcage Package существует, иначе ложь.

  2. 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 выполнит предложение правой стороны, только если выполнение слева возвращает не ложное значение

Другие вопросы по тегам