Как я могу определить, существует ли функция Perl во время выполнения?

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

eval "&verify_precondition_TEST$n";
print $@ if $@;

К сожалению, это выводит «Неопределенная подпрограмма & verify_precondition_TEST1, вызванная в ...», если функция не существует.

Как я могу заранее определить, существует ли функция, прежде чем пытаться ее вызвать?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
23
0
19 300
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Package::Name->can('function')

или же

*Package::Name::function{CODE}

# or no strict; *{ "Package::Name::$function" }{CODE}

или просто жить с исключением. Если вы вызываете функцию в eval и установлен $ @, вы не можете вызвать функцию.

Наконец, похоже, что вы можете захотеть Test :: Class вместо того, чтобы писать это самостоятельно.

Обновлено: defined &function_name (или вариант no strict; defined &{ $function_name }), как упоминалось в других ответах, выглядит лучшим способом. UNIVERSAL :: can лучше всего подходит для того, что вы собираетесь вызывать как метод (стилистически), и зачем возиться с таблицей символов, когда Perl дает вам синтаксис для выполнения того, что вы хотите.

Обучение ++ :)

К сожалению, я делаю это вне любого пакета, поэтому получаю: Не могу найти метод объекта "can" через пакет "main". Кроме того, я использую старую версию Perl (5.002) в среде, где у меня абсолютно не установлены модули Perl.

Greg Hewgill 12.01.2009 01:18

Ого, 5.002? Думаю, это появилось еще до моего рождения :)

jrockway 12.01.2009 01:30

Разве 5.002 - не тот, у которого все проблемы с переполнением буфера? :)

brian d foy 12.01.2009 21:55

Согласно perlhist, 5.003 - это 5.002 с исправлениями безопасности.

jrockway 12.01.2009 22:57

(И, по-видимому, тогда у них не было UNIVERSAL ::. Вот почему main-> может не работать; он отлично работает под 5.10.)

jrockway 12.01.2009 22:58

@Greg Hewgill, вы никогда не выходите за пределы пакета. Попробуйте main-> can ("функция")

Chas. Owens 04.08.2009 22:12

@GregHewgill - мне интересно ваше окружение. Не могли бы вы сказать несколько слов об этом? Звучит как большой пример использования «древних» платформ до сегодняшнего дня ...

jm666 18.02.2014 13:18

@ jm666: Я думаю, что в то время это была разновидность OSF / 1 или AIX. Установленный Perl поставлялся вместе с ОС, и попытки его обновления не стоили усилий.

Greg Hewgill 18.02.2014 13:23
Ответ принят как подходящий

С определением:

if (eval "defined(&verify_precondition_TEST$n)") {
    eval "&verify_precondition_TEST$n";
    print $@ if $@;
}
else {
    print "verify_precondition_TEST$n does not exist\n";
}

Обновлено: хм, я думал только об eval, поскольку он был в вопросе, но с символическими ссылками, поднятыми с Леоном Тиммермансом, не могли бы вы сделать

if (defined(&{"verify_precondition_TEST$n"}) {
    &{"verify_precondition_TEST$n"};
    print $@ if $@;
}
else {
    print "verify_precondition_TEST$n does not exist\n";
}

даже со строгим?

Это неправильный eval. Вам нужен блок eval, а не строковый eval. Плюс тестирование, существует ли функция, в любом случае можно выполнить с помощью eval.

Dave Rolsky 12.01.2009 01:51

Мне нужно использовать строку eval, потому что $ n неизвестно во время компиляции.

Greg Hewgill 12.01.2009 01:59

Нет, не знаешь. Вам нужно использовать символические ссылки. См. Мой ответ как пример того, как к ним подойти.

Leon Timmermans 12.01.2009 04:24

Вы правы, определенное освобождается от строгих рекомендаций. Однако вызов субмарины - нет. Вы должны либо использовать «no strict», либо использовать eval, первый будет более чистым IMNSHO.

Leon Timmermans 12.01.2009 19:37

Кроме того, вам нужно использовать имя пакета, если функция определена в каком-то пакете ... например, use CGI; my $q=CGI->new; my @users = defined (&CGI::multi_param) ? $q->multi_param('u') : $q->param('u');

Matija Nalis 03.04.2018 16:32
sub function_exists {    
    no strict 'refs';
    my $funcname = shift;
    return \&{$funcname} if defined &{$funcname};
    return;
}

if (my $subref = function_exists("verify_precondition_TEST$n") {
    ...
}

+1 (отсутствие строгого всегда лучше, чем строка eval) Кстати, крошечная опечатка: s / $ functname / $ funcname /

jrockway 12.01.2009 04:53

Я бы написал это как no strict 'refs', чтобы заметить читателю, что вы собираетесь совершить некоторую магию символических ссылок. :)

brian d foy 12.01.2009 21:54

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

my %symbols = ();
my $package =__PACKAGE__; #bring it in at run-time
{
    no strict;
    %symbols = %{$package . "::"}; #See Symbol Tables on perlmod
}
print "$funcname not defined\n" if (! defined($symbols{$funcname});

Ссылки:
Ссылка __УПАКОВКА__ на странице perlmod.

Пакеты / __ ПАКЕТ__ ссылка на обучение Perl в Австралии.

Проблема может быть в том, что вы пытались сделать напрямую, например: if ( defined &{$package . '::subname'} ), но вроде этого должно быть хорошо: my $subname = $package.'::sub_name'; if ( defined &{$subname} ) ...

bor 05.09.2014 14:24

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