Анимация
JavaScript
|
Главная Библионтека 10.15. Перехват вызовов неопределенных функций с помощью AUTOLOAD .$name = sub ($) { XFONT COLOR=$name>$ [0]</FONT>" }; Однако прототип проверяется во время компиляции, поэтому приведенное выше присваивание произойдет слишком поздно и никакой пользы не принесет. Следовательно, весь цикл с присваиваниями следует включить в BEGIN-блок, чтобы форсировать его выполнение при компиляции. > Смотри также- Описание замыканий в perlref{\); раздел «Symbol tables» perlmod(i)] рецепты 10.11; 11.4. 10.15. Перехват вызовов неопределенных функций с помощью AUTOLOAD проблема Требуется перехватить вызовы неопределенных функций и достойно обработать их. Решение Объявите функцию с именем AUTOLOAD для пакета, вызовы неопределенных функций которого вы собираетесь перехватывать. Во время ее выполнения переменная $AUTOLOAD этого пакета содержит имя вызванной неопределенной функции. Комментарий В подобных ситуациях обычно применяются вспомогательные функции (proxy). При вызове неопределенной функции вместо автоматического инициирования исключения также можно перехватить вызов. Если пакет, к которому принадлежит вызываемая функция, содержит функцию с именем AUTOLOAD, то она будет вызвана вместо неопределенной функции, а специальной глобальной переменной пакета $AUTOLOAD будет присвоено полное имя функции. Затем функция AUTOLOAD сможет делать все, что должна была делать исходная функция. sub AUTOLOAD { use vars qw($AUT0LOAD); my Scolor = $AUTOLOAD; Scolor =~ s/,: ; return "<FONT C0LOR=Scolor>i8i </F0NT>"; # Примечание: функция sub chartreuse не определена print chartreuseCstuff); При вызове несуществующей функции main: :chartreuse вместо инициирования исключения будет вызвана функция main: :AUTOLOAD с аргументами, переданными chartreuse. Пакетная переменная $AUTOLOAD будет содержать строку main: :chartreuse. Методика с присваиваниями тип-глобов из рецепта 10.14 быстрее и удобнее. Быстрее - поскольку вам не приходится запускать копию и заниматься подстановками. Удобнее - поскольку вы сможете делать следующее: local »yellow = \&violet; local (Ted, *green) = (\&green, \&red); print stuff(); При работе print stuf f или любой вызванной ей функции все, что должно выводиться желтым цветом, выводится фиолетовым; красный цвет заменяется зеленым, и наоборот. Однако подстановка функций не позволяет обрабатывать вызовы неопределенных функций. AUTOLOAD снравляется с этой проблемой. > Смотри также- Раздел «Autoloading» perisub(l); документация по стандартным модулям Auto-Loader и AutoSplit; рецепты 10.12; 12.10; 13.11. 10.16. Вложенные подпрограммы Проблема Требуется реализовать вложение подпрограмм, чтобы одна подпрограмма была видна и могла вызываться только из другой. Если попытаться применить очевидный вариант sub FOO { sub BAR { } . . }, Perl предупреждает о переменных, которые «пе останутся общими». Решение Вместо того чтобы оформлять внутренние функции в виде обычных подпрограмм, реализуйте их в виде замыканий и затем временно присвойте их тип-глобу правого имени, чтобы создать локальную функцию. Комментарий Вероятно, в других языках программирования вам приходилось работать с вложенными функциями, обладающими собственными закрытыми переменными. В Perl для этого придется немного потрудиться. Интуитивная реализация приводит к выдаче предупреждения. Например, следующий фрагмент не работает; sub outer { my $х = $ [0] + 35, sub inner { return $x . 19 } # НЕВЕРНО return $x + innerO; 10.17. Сортировка почты 373 Обходное решение выглядит так: sub outer { my $х = $ [0] + 35; local inner = sub { return $x * 19 }; return $x + innerO; Теперь благодаря Bpeivienno присвоенному замыканию inner() может вызываться только из outer(). При вызове inner() получает нормальный доступ к лексической переменной $х из области действия outer(). В сущности, мы создаем функцию, которая является локальной для другой функции - подобная возможность не поддерживается в Perl напрямую. Впрочем, ее реализация не всегда выглядит понятно. > Смотри также- Описание замыканий в perlref{\); раздел «Symbol tables* perlmod{i); рецепты 10.13-10.14. 10.17. Сортировка почты Программа из примера 10.1 сортирует почтовый ящик по темам. Для этого она читает сообщения по абзацам и ищет абзац, начинающийся с Fom;". Когда такой абзац будет найден, программа ищет тему, удаляет из нее все пометки "Re:", преобразует в нижний регистр и сохраняет в массиве @Sl)D. При этом сами сообщения сохраняются в массиве (Smsgs. Переменная $msgno следит за номером сообщения. Пример 10.1. bysubl «/usr/bin/perl « bysubl - simple sort by subject my(@msgs, @sub); my $msgno = -1; $/=: « Чтение no абзацам while (<>) { If (/"From/m) { /•Sub]ecf\s*(:Re:\sO*( *)/mi; $sub[++$msgno] = lc($1) ; $msgs[$msgno] .= $ ; for my $1 (sort { $sub[$a] cmp $sub[$b] $a <=> $b } (0 . . $«msgs)) { print $msgs[$i]; В этом варианте сортируются только индексы массивов. Если темы совпадают, стр возвращает О, поэтому используется вторая часть , в которой номера сообщений сравниваются в порядке их исходного следования. 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 |