Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 [ 116 ] 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

10.12. Обработка исключений 365

Комментарий

Инициирование исключения - крайняя мера, и относиться к ней следует серьезно. В большинстве функций следует возвращать признак ошибки с помощью простого оператора return. Перехватывать исключения при каждом вызове функции скучно и некрасиво, и это может отпугнуть от применения исключений.

Но в некоторых ситуациях неудачный вызов функции должен приводить к аварийно.му завершению программы. Вместо невосстановимой функции exit следует вызвать die - по крайней мере, у программиста появится возможность вмешаться в происходящее. Если ни один обработчик исключения не был установлен с помощью eval, на этом месте программа аварийно завершается.

Чтобы обнаружить подобные нарушения, можно поместить вызов функции в блок eval. Если произойдет исключение, оно будет присвоено переменной $@; в противном случае переменная равна false.

eval { $val = func() );

warn "func blew up: $(a" if $(a;

Блок eval перехватывает все исключения, a не только те, что интересуют вас. Непредусмотренные исключения обычно следует передать внешнему обработчику. Предположим, функция инициирует исключение, описываемое строкой "Full moon!". Можно спокойно перехватить это исключение и дать другим обработчикам просмотреть переменную $@. При вызове die без аргументов новая строка исключения конструируется на основант! содержимого $@ и текущего контекста.

eval { $val = func() };

If ($(a && $(a ! - /Full moon!/) {

die; » Повторно инициировать неизвестные ошибки

Если функция является частью модуля, можно использовать модуль Сагр и вызвать croak или confess вместо die. Единственное отличие die от croak заключается в том, что croak представляет ошибку с позиции вызывающей стороны, а не модуля. Функция confess по содержимому стека определяет, кто кого вызвал и с какими аргументами.

Другая интересная возможность заключается в том, чтобы функция могла узнать о полном игнорировании возвращаемого ею значения (то есть о том, что она вызывается в неопределенном контексте). В этом случае возвращение кода ошибки бесполезно, поэтому вместо него следует инициировать исключение.

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

if (defined wantarrayO) { return;

) else {

die "pay attention to my error!";

> Смотри также ---

Описание переменной $@ вperlvar(i); описание функций die и aval вреН/ипс(1); рецепты 10.15, 12.2 и 16.21.



10.13. Сохранение глобальных значений

проблема

Требуется временно сохранить значение глобальной неременной.

Решение

Воспользуйтесь оператором local, чтобы сохранить старое значение и автоматически восстановить его при выходе из текущего блока:

$аде = 18; # Глобальная переменная

if (CONDITION) { local $age = 23;

funcO; # Видит временное значение 23

} # Восстановить старое значение при выходе из блока

Комментарий

к сожалению, оператор Perl local не создает локальной переменной - это делается оператором ту. local всего лищь сохраняет существующее значение на время выполнения блока, в котором он находится.

Однако в трех ситуациях вы должны использовать local вместо ту.

1. Глобальной неременной (особенно $ ) присваивается временное значение.

2. Создается локальный манипулятор файла или каталога или локальная функция.

3. Вы хотите временно изменить один элемент массива или хэша.

Применение 1оса1() для присваивания временных значений глобальным переменным

Первая ситуация чаще встречается для стандартных, нежели пользовательских переменных. Нередко эти переменные иснользуются Perl в высокоуровневых операциях. В частности, любая функция, явно или косвенно использующая $ , должна иметь локальную копию $ . Об этом часто забывают. Одно из возможных решений приведено в рецепте 13.15.

В следующем примере используется несколько глобальных неременных. Переменная $/ косвенно влияет на поведение оператора чтения строк, используемого в операциях <FH>.

$рага = get paragraph(*FH); Я Передать glob файлового манипулятора

$рага = get paragraph(\*FH); Я Передать манипулятор по ссылке на glob

$рага = get paragraph(*IO{FH}); # Передать манипулятор по ссылке на 10 sub get paragraph {

my $fh = shift;

local $/ = " ;

my Sparagraph = <$fh>;

chomp($paragraph);

return Sparagraph;



10.13. Сохранение глобальных значений 367

Применение 1оса1() для создания локальных манипуляторов

Вторая ситуация возникает в случае, когда требуется локальный манипулятор файла или каталога, реже - локальная функция. Начиная с Perl версий 5.000, можно воспользоваться стандартными модулями Symbol, Filehandle или IO::Handle, но и привычная методика с тии-глобом по-прежнему работает. Например:

Scontents = get motd(); sub get motd { local .MOID;

open(MOTD, "/etc/motd") or die "cant open motd: $!";

local $/ = undef; # Читать весь файл local $ = <MOTD>; close (MOTD); return $ ;

Открытый файловый манипулятор возвращается следующим образом: return *MOTD;

Применение 1оса1() в массивах и хэшах

Третья ситуация на практике почти не встречается. Поскольку оператор local в действительности является оператором «сохранения значения», им можно воспользоваться для сохранения одного элемента массива или хэша, даже если сам массив или хэщ является лексическим!

ту (ginums = (О . . 5); sub first {

local $nums[3] = 3.14159;

secondO;

sub second {

print "(JnumsXn";

secondO; 0 1 2 3 4 5

firstO;

0 1 2 3.14159 4 5

Единственное стандартное применение - временные обработчики сигналов.

sub first {

local $SIG{INT} = IGNORE; secondO;

Теперь BO время работы secon(J() сигналы прерывания будут игнорироваться. После выхода из first () автоматически восстанавливается предыдущее значение $SIG{INT}.

Хотя local часто встречается в старом коде, от него следует держаться подальше, если это только возможно. Поскольку local манипулирует значениями



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 [ 116 ] 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242