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

# Выбрать различные значения, включая нулевого друга printf "At age %d, %ss first friend is %s.\n", $p->age, $p->name, $p->peers(0);

ластью действия). Только методы класса могут напрямую обращаться к атрибутам класса. Методы объектов работают только с данными объектов. Если методу объекта потребуется обратиться к данным класса, его конструктор должен сохранить ссылку на эти данные в объекте. Пример:

sub new {

my Sclass = shift; my Sself = bless({>, Sclass); $self->{Max Bounds ref> = \$Bounds; return Sself,

>

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

perltoot(\.), perlobj{i) w perlbot{\); рецепт 13.3; пример использования метода places в разделе «Пример. Перегруженный класс FixNum» в рецепте 13.14.

13.5. Использование класса как структуры

Проблема

Вы привыкли работать со структурированными типами данных - более сложными, чем массивы и хэщи Perl (например, структуры С и записи Pascal). Вы слыща-ли о том, что классы Perl не уступают им по возможностям, но не хотите изучать объектно-ориентированное программирование.

Решение

Воспользуйтесь стандартным модулем Class::Struct для объявления С-подобных структур:

use Class;;Struct, # Загрузить модуль построения структур

struct Person => { (t Создать определение класса "Person"

name =>$, tt Имя - скаляр

age =>$, tt Возраст - тоже скаляр

peers => @, # Но сведения о друзьях - массив (ссылка)

>:

ту $р = Person->new(); # Выделить память для пустой структуры Person

$p->name("Jason Smythe"), # Задать имя

$p->age(13); # Задать возраст

$p->peers( ["Wilbur", "Ralph", "Fred ] ); # Задать друзей

tt Или так;

p->peersi = ("Wilbur", "Ralph", "Fred");



13.5. Использование класса как структуры 465

Комментарий

Функция Class: : St ruct: struct автоматически создает классы, дублирующие структуры. Она создает класс с именем, передаваемым в первом аргументе, и генерирует для него конструктор new и методы доступа к полям.

В определении структуры ключи соответствуют именам полей, а значения - типам данных. Существуют три основных значения типа: $ для скаляров, @ для массивов и % для хэщей. Каждый метод доступа может вызываться без аргументов (выборка текущего значения) или с аргументами (присваивание значения). Для полей с типом «массив» или «хэщ» вызов метода без аргументов возвращает ссылку на весь массив или хэщ, вызов с одним аргументом получает значение по указанному индексу, а вызов с двумя аргументами задает значение для указанного индекса.

Однако тип может быть именем другой структуры (или любого класса), имеющей конструктор new.

use Class:Struct,

struct Person => {name => $, age => $};

struct Family => {head => Person , address => $ , members => @},

$folks = Family->new(); $dad = $folks->head, $dad->name("John"); $dad->age(34);

printf(%ss age is %d\n", $folks->head->name, $folks->head->age).

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

sub Person::age { use Carp,

my ($self, $age) = @ ;

If (@ > 2) { confess "too many arguments" } elsif (@ == 1) { return $struct->{ age> }

elsif (@ == 2) {

carp "age $age isnt numeric" if $age i~ /"\d+/;

carp "age $age is unreasonable" if $age > 150;

$self->{age} = $age,

>

Если предупреждения должны выводиться лищь при наличии флага -w в командной строке, проверьте переменную $"W:

Если только оно не является ссылкой; в этом случае используется субъектная структура данных с проверкой типа.



If ($"W) {

carp "age Sage isnt numeric" if Sage ! /"\d+/; carp "age Sage is unreasonable" if Sage > 150;

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

ту Sgripe = $"W ? \&carp : \&croak;

$gripe->("age Sage isnt numeric") if Sage !~ /"\d+/; $gripe->("age Sage is unreasonable") if Sage > 150;

Как и большинство классов, наш класс реализован в виде хэша. Это упрощает отладку и сопровождение кода. Представьте себе возможность вывода структуры в отладчике. Однако модуль Class::Struct также поддерживает реализацию на базе массива, для этого достаточно перечислить поля в квадратных скобках вместо фигурных;

struct Family => [head => Person, address => $, members => §];

Существуют эмпирические данные, свидетельствующие о том, что выбор массива вместо хэша снижает расходы памяти от 10 до 50 % и примерно на 33 % ускоряет доступ. За это приходится расплачиваться менее содержательной отладочной информацией и трудностями при написании переопределяющих функций (таких, как приведенная выше функция Person::age). Обычно представление объекта в виде массива усложняет наследование. В данном случае это не так, поскольку С-по-добные структуры обеспечивают намного более понятную реализацию агрегирования.

Директива use fields в Perl версии 5.005 повышает скорость за счет дополнительных затрат памяти и обеспечивает проверку имен полей на стадии компиляции.

Если все поля принадлежат к одному типу, то запись вида;

struct Card => { name => $, color => $, cost => $, type => $, release => $, text => S,

упрощается с помощью функции map;

struct Card => map {$ =>$ } qw(name color cost type release text);

A если вы программируете на С и предпочитаете указывать тип поля перед его именем, а не наоборот, просто измените их порядок:

struct hostent => { reverse qw{ $ name



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