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

ненно обладает собственным состоянием, поведением и идентификацией, а также обеспечивает инкансуляцию.

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

Замыкания рассматриваются в perlref(l). Также см. главу 13, рецепты 10.11; 11.4.

11.8. Создание ссылок на методы

Проблема

Требуется сохранить ссылку на метод.

Решение

Создайте замыкание, обеспечивающее вызов нужного метода для объекта.

Комментарий

Ссылка на метод - это нечто большее, чем простой указатель на функцию. Вам также придется определить, для какого объекта вызывается метод, поскольку ис-ход}1ые данные для работы метода содержатся в объекте. Оптимальным решением будет использование замьп<апия. Если неременная $obj имеет лексическую область действия, воспользуйтесь следующим фрагментом:

$mref = sub { $ob]->meth(@ ) }; # Позднее...

$mref->("args", "go", "here");

Даже когда неременная $obj выходит из области действия, она остается в замыкании, хранящемся в $mref. Позднее при косвенном вызове метода будет использован правильный объект.

Учтите, что формулировка:

Ssref = \$obj->meth;

работает не так, как можно предположить. Сначала она вызывает метод объекта, а затем дает ссылку либо на возвращаемое значе}И1е, либо па последнее из возвращаемых значений, если метод возвращает список.

Метод сап из базового класса UNIVERSAL выглядит заманчиво, но вряд ли делает именно то, что вы хотите:

Scref = $obj->can("meth");

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

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

Описание методов во введении к главе 13; рецепты 11.7; 13.7.



11.9. Конструирование записей 393

11.9. Конструирование записей

Проблема

Требуется создать тип данных для хранения атрибутов (запись).

Решение

Воспользуйтесь ссылкой на анонимный хэш.

Комментарий

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

Srecord = {

NAME => Jason-,

EMPNO => 132,

TITLE => "deputy peon",

AGE => 23,

SALARY => 37 000,

PALS => [ "Norbert", "Rhys, "Phineas"],

printf "I am %s, and my pals are %s,\n", Srecord->{NAME}, join(", ", @{Srecord->{PALS}});

Впрочем, от отдельной записи толку мало - хотелось бы построить структуры данных более высокого уровня. Например, можно создать хэш %ByName, а затем инициализировать и использовать его следуюп[им образом:

й Сохранить запись

Sbyname{ Srecord->{NAME} } = Srecord; К Позднее искать по имени

if (Srp = Sbyname{"Aron"}) { # false, если отсутствует missing

printf "Aron is employee %d \n", $rp->{EMPNO};

# Дать Джейсону нового друга

push @{Sbyname{"Jason"}->{PALS}}, "Theodore";

printf "Jason now has %d pals\n", scalar (9i{Sbyname{"Jason"}->{PALS}};

В результате %Ьупате превращается в хэш хэшей, поскольку хранящиеся в нем значения представляют собой ссылки на хэши. Поиск работника но имени с ири-мене}шем такой структуры оказывается простой задачей. Если значение найдено в хэше, мы сохраняем ссылку на запись во временной переменной $гр, с помощью которой далее можно получить любое нужное поле.

Для операций с %byname можно использовать стандартные средства работы с хэшами. Например, итератор each организует перебор элементов в произвольном порядке:



# Перебор всех записей

while ((Sname, Srecord) = each %byname) {

printf "%s IS employee number %d\n", Sname, $record->{EMPNO},

A как насчет поиска работников но номеру? Достаточно построить другую структуру данных - массив хэшей ©employees. Если работники нумеруются непоследовательно (скажем, после 1 следует номер 159997), выбор массива окажется неудачным. Вместо этого следует воспользоваться хэшем, в котором номер работника ассоциируется с записью. Для последовательной нумерации подойдет и массив:

й Сохранить запись

$employees[ $record->{EMPNO} ] = Srecord,

й Поиск по номеру

If (Srp = $employee[132]) {

printf employee number 132 is %s\n , $rp->{NAME},

При работе с подобными структурами дан}1ых обновление записи в одном месте обновляет ее везде. Например, следующая команда повышает жалование Джейсо-на на 3,5%:

$byname{Jason}->{SALARY} *= 1 035,

Внесенные изменения отражаются во всех представлениях этих записей. Помните о том, что $byname{ Jason } и $employees[l32] ссылаются на одну и ту же запись, поскольку хранящиеся в них ссылки относятся к одному анонимному хэшу.

Как отобрать все заниси, удовлетворяющие некоторому критерию? Для этого и была создана функция grep. Например, в следующем фрагменте отбираются два подмножества записей - работников, чья должность содержит слово "peon", и тех, чей возраст равен 27 годам.

@peons = grep { $ ->{TlTLE} =~ /реоп/i } gemployees, @tsevens = grep { $ ->{AGE} == 27 } employees;

Каждый элемент @peons и @tsevens представляет собой ссылку на запись, поэтому они, как и @employees, являются массивами хэшей.

Вывод записей в определенном порядке (например, по возрасту) выполняется так:

# Перебрать все записи

foreach $гр (sort { Sa->{AGE} <=> $b->{AGE} } values %byname) { printf %s IS age %d.\n", $rp->{NAME}, Srp->{AGE}; # или со срезом хэша через ссылку

printf "%s IS employee number %d.\n", eSrpiNAME, EMPNO};

Вместо того чтобы тратить время на сортировку по возрасту, можно просто создать для этих записей другое представление, @byage. Каждый элемент массива (например, $byage[27]) является массивом всех записей с данным возрастом. Фактически мы получаем массив массивов хэшей. Он строится так:



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