Анимация
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

"О but true" (для удобства эта волшебная строка была изъята из бесчисленных предупреждений об ошибках преобразования флага -w). Появляется возможность использовать конструкции следуюшего вида:

ioctl(,,.,) or die "cant ioctl: $!";

В этом случае программе не нужно отличать определенный ноль от неопределенного значения, как пришлось бы делать для функций read или glob. В числовой интерпретации "О but true" является нулем. Необходимость в возвращении подобных значений возникает довольно редко. Более распространенный (и эффектный) способ сообщить о неудаче при вызове функции заключается в инициировании исключения (см. рецепт 10.12).

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

Описание функций wantarray и return вperlfunc(l); рецепт 10.12.

10.11. Прототипы функций

Проблема

Вы хотите использовать прототипы функций, чтобы компилятор мог проверить типы аргументов.

Решение

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

Комментарий

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

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

Прототип принудительно задает контекст аргументов, используемых при вызове данной функции. Это происходит во время компиляции программы и в большинстве случаев вовсе не означает, что Perl проверяет количество или тип аргументов функции. Если Perl встретит вызов func(3, 5) для функции с прото-



10.11. Прототипы функций 363

типом sub func($), он завершит компиляцию с ошибкой. Но если для того же прототипа встретится вызов func(@array), компилятор всего лишь преобразует @аггау в скалярный контекст; он не скажет: «Массив передавать нельзя - здесь должна быть скалярная величина».

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

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

Пропуск скобок

Обычно функция получает список аргументов, и при вызове скобки ставить не обязательно:

(giresults = myfunc 3 , 5;

Без прототипа такая запись эквивалентна следующей:

©results = myfunc(3 , 5);

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

sub myfunc($);

©results = myfunc 3 , 5;

Теперь эта запись эквивалентна следующей;

©results = ( myfunc(3), 5 );

Кроме того, можно предоставить пустой прототип, показывающий, что функция вызывается без аргументов, как встроенная функция time. Именно так реализованы константы LOCK SH, LOCK EX и LOCK UN в модуле Fcntl. Они представляют собой экспортируемые функции, определенные с пустым прототипом:

sub LOCK SH О { 1 ) sub LOCK EX 0(2} sub LOCK UN 0(4}

Имитация встроенных функций

Прототипы также часто применяются для имитации поведения таких встроенных функций, как push и shift, передающих аргументы без сглаживания. При вызове push(@array, 1, 2, 3) функция получает ссылку на @аггау вместо самого массива. Для этого в прототипе перед символом @ ставится обратная косая черта:

sub mypush (\(s>@) { my $array ref = shift; my ©remainder = © ;



\@ в прототипе означает «потребовать, чтобы первый аргумент начинался с символа @, и передавать его по ссылке». Второй символ @ говорит о том, что остальные аргументы образуют список (возможно, пустой). Обратная косая черта, с которой начинается список аргументов, несколько ограничивает ваши возможности. Например, вам даже не удастся использовать условную конструкцию ?: для выбора передаваемого массива:

mypush( $х > 10 ? @а : (ЭЬ , 3, 5 ); # НЕВЕРНО

Вместо этого приходится изощряться со ссылками:

mypush( (а{ $х > 10 ? (Эа : * }, 3, 5 ); й ВЕРНО

Приведенная ниже функция hpush работает аналогично push, но для хэшей. Функция дописывает в существующий хэш список пар «ключ/значение», переопределяя прежнее содержимое этих ключей.

sub hpush(\%(s>) {

my $href = shift;

while ( my ($k, $v) = splice((a , 0, 2) ) { $href->{$k) = $v;

hpush(%pieces, "queen" => 9, "rook" => 5);

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

Описание функции prototype вperlfunc(l);perlsub(l); рецепт 10.5.

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

Проблема

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

Решение

Иногда в программе возникает что-то настолько серьезное, что простого возвращения ошибки оказывается недостаточно, поскольку та может быть проигнорирована вызывающей стороной. Включите в функцию конструкцию die СТРОКА, чтобы инициировать исключение:

die "some message"; fl Инициировать исключение

Чтобы перехватить исключение, вызывающая сторона вызывает функцию из eval, после чего узнает результат с помощью специальной неременной $@:

eval { func() }; if ($@) {

warn "tunc raised an exception: $(a";



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