Анимация
JavaScript
|
Главная Библионтека 10.3. Создание устойчивых закрытых переменных 353 внешней области, поскольку определяется в одной области действия с этими переменными. Именованные подпрограммы не следует объявлять внутри объявлений других именованных подпрограмм. Такие подпрограммы, в отличие от полноценных замыканий, не обеспечивают правильной привязки лексических переменных. В рецепте 10.16 показано, как справиться с этим ограничением. При выходе лексической переменной за пределы области действия занимаемая ей память освобождается, если на нее не существует ссылок, как для массива (giarguments в следующем фрагменте: sub save array { my arguments = @ ; push(@Global Array, \@arguments), Система сборки мусора Perl знает о том, что память следует освобождать лишь для неиспользуемых объектов. Это и позволяет избежать утечки памяти при возвращении ссылки на закрытую переменную. > Смотри также- Ра.здел «Private Variables via my()»perlsub(i). 10.3. Создание устойчивых закрытых переменных Проблема Вы хотите, чтобы переменная сохраняла значение между вызовами подпрограммы, но не была доступна за ее пределами. Например, функция может запоминать, сколько раз она была вызвана. Решение «Заверните» фушсцию во внешти! блок и объявите переменные ту в области действия этого блока, а не в самой функции: ту Svariable, sub mysub { # . обращение к $variable Если переменные требуют инициализации, снабдите блок ключевым словом BEGIN, чтобы значение переменных заведомо задавалось перед началом работы основной программы: BEGIN { my Svariable =1, # Начальное значение sub othersub { # обращение к Svariable Комментарий в отличие от локальных переменных в языках С и С++, лексические переменные Perl не всегда уничтожаются при выходе из области действия. Если нечто, продолжающее существовать, все еще помнит о лексической переменной, намять не освобождается. В нащем примере mysub использует переменную Svanable, поэтому Perl не освобождает память переменной при завершении блока, вмещающего определение mysub. Счетчик вызовов реализуется следующим образом: ray $counter, sub next counter { return ++$counter } При каждом вызове next counter функция увеличивает и возвращает переменную Scounter. При первом вызове переменная $counter имеет неопределенное значение, поэтому для оператора ++ она интерпретируется как 0. Переменная входит не в область действия next counter, а в окружающий ее блок. Никакой внешний код не сможет изменить $counter без вызова next counter. Для расширения области действия обычно следует использовать ключевое слово BEGIN. В противном случае возможен вызов функции до инициализации переменной. BEGIN { my Scounter = 42, sub next counter { return ++$counter } sub prev counter { return --$counter } Таким образом, в Perl создается аналог статических переменных языка С. В действительности он даже лучше - переменная не ограничивается одной функцией, и обе функции могут совместно использовать свою закрытую переменную. > Смотри также- Раздел «Private Variables via my()» perlsub{i); раздел «Package Constructors and Destructors* perlmod{l); рецепт 11.4. 10.4. Определение имени текущей функции Проблема Требуется определить имя функции, работающей в настоящий момент. Оно пригодится для сообщений об ошибках, которые не изменяются при копировании/ вставке исходного текста подпрограммы. 10.4. Определение имени текущей функции 355 Решение Воспользуйтесь функцией caller: $this function = (caller(0))[3], Комментарий Программа всегда может определить текущей номер строки с помощью специальной метапеременной LINE . Текущий файл определяется с помощью мета-переменной FILE , а текущий пакет - PACKAGE . Однако не существует метапеременной для определения имени текущей подпрограммы, не говоря уже об имени той, из которой она была вызвана. Встроенная функция caller справляется со всеми затруднениями В скалярном контексте она возвращает имя пакета вызывающей функции, а в списковом контексте возвращается список с разнообразными сведениями. Функции также можно передать число, определяющее уровень вложенности получаемой информации: О - ваща функция, 1 - функция, из которой она была вызвана, и т. д. Полный синтаксис выглядит следующим образом ($i - количество уровней вложенности): ($раскаде, Sfilename $line $subr $has args Swantarray )= caller($i) # 0 1 2 3 4 5 Возвращаемые значения имеют следующий смысл: Spackage Пакет, в котором был откомпилирован код: Sfilename Имя файла, в котором был откомпилирован код Значение -е возвращается при запуске из командной строки, а значение - (дефис) - при чтении сценария из STDIN. Sline Номер строки, из которой был вызван данный кадр стека: Ssubr Имя функции данного кадра, включающее ее пакет. Замыкания возвращают имена вида main ANON , вызов по ним невозможен. Для eval возвращается (eval) . Shas args Признак наличия аргументов при вызове функции: Swantarray Значение, возвращаемое функцией wantarray для данного кадра стека. Равно либо true, либо false, либо undef. Сообщает, что функция была вызвана в списковом, скалярном или неопределенном контексте. Вместо непосредственного вызова caller, продемонстрированного в рещении, можно написать вспомогательные функции: Sme = whoamiO, 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 |