Строка 458: |
Строка 458: |
| | | |
| = Оператор разыменования = | | = Оператор разыменования = |
| + | |
| + | Если ссылка на объект хранится в одной переменной, то доступ к собственным переменным и процедурам объекта можно получить с помощью операторов, описанных в следующих разделах. Такая операция называется разыменованием переменной, поскольку она требует от компьютера доступа к данным, на которые указывает ссылка. |
| + | |
| + | == «строгая» отсылка == |
| + | |
| + | Оператор "." (точка) используется для доступа к переменной или процедуре, принадлежащей объекту. Для этого необходимо, чтобы ссылка на объект хранилась в переменной соответствующего типа. Тип не обязательно должен быть полностью определен - достаточно, чтобы перейти к определению переменных и процедур, к которым будет осуществляться доступ. |
| + | |
| + | object.variable 20pt Or 20pt object.procedure() |
| + | |
| + | В отличие от большинства других операторов DM, пробел не допускается по обе стороны от оператора точки. Имена переменных и процедур должны располагаться по обе стороны от него без разделения. |
| + | |
| + | Требование, чтобы объект принадлежал к известному типу, просто позволяет компилятору лучше проверять ошибки. Он не позволит вам попытаться получить доступ к переменной или процедуре, которая не принадлежит к указанному типу, и поэтому известен как «строгий» оператор разыменования. |
| + | |
| + | Это во время компиляции. Во время выполнения вы можете присвоить переменную объекту, который даже не имеет того же типа (например, mob в переменной obj). Это не страшно. Фактически, оператор ''dot'' будет работать и в этом случае, если запрашиваемая переменная существует для данного объекта. В этом случае мы говорим, что объект имеет совместимый интерфейс. |
| + | |
| + | Если во время выполнения выясняется, что у объекта нет запрошенной переменной, процедура немедленно прекращает выполнение. Это называется крахом процедуры. (Еще хуже - мировой крах, при котором погибает весь мир). Наиболее распространенный случай - нулевой объект. При этом будет выдан отладочный вывод, описывающий точную причину, чтобы помочь вам отследить проблему. Более подробно методы отладки будут рассмотрены в главе 19. |
| + | |
| + | Следующие четыре ''verb'' иллюстрируют различные свойства оператора ''dot''. |
| + | |
| + | mob/verb |
| + | summon1(M as mob) |
| + | M.loc = loc //compile-time error! |
| + | summon2(mob/M) |
| + | M.loc = loc //this works |
| + | summon3(obj/M as mob) |
| + | M.loc = loc //this works |
| + | summon4(mob/M as mob|null) |
| + | M.loc = loc //could be run-time error! |
| + | |
| + | Первая версия ''verb/summon'' не компилируется. Входной тип M был определен как mob, но тип переменной остался неопределенным, поэтому компилятор не знает, что в M есть переменная ''loc''. |
| + | |
| + | Вторая версия заботится о типе переменной и использует тот факт, что тип ввода по умолчанию вычисляется из типа переменной. |
| + | |
| + | Третья версия странная, но она работает. Мы сказали компилятору, что это переменная obj, и сказали клиенту принимать мобов в качестве входных данных. Поскольку и obj, и mob имеют переменную loc, и компилятор, и сервер довольны. Вы, конечно, не захотите делать все именно так, но вы можете изменить тип ввода на obj|mob, и это будет более логично. |
| + | |
| + | Четвертая версия рискует привести к аварийному завершению работы ''proc''. Вместо этого следует проверять, не является ли M нулем, и не разыменовывать его в этом случае. Другой способ - присвоить M значение по умолчанию (например, ''usr''). |
| + | |
| + | == «слабая» отсылка == |
| + | |
| + | Оператор ":" позволяет сделать еще один шаг вперед, сделав проверку валидности во время компиляции еще менее строгой. Он работает так же, как оператор ''dot'', только полный тип объекта указывать не нужно. Пока хотя бы один объектный тип, производный от указанного, содержит запрашиваемую переменную, компилятор будет ее разрешать. Вам остается следить за тем, чтобы во время выполнения использовались только совместимые объекты (иначе произойдет сбой). |
| + | |
| + | variable:variable 20pt Or 20pt variable:procedure() |
| + | |
| + | Как и оператор ''dot'', оператор ":" не может иметь пробелов между собой и своими аргументами. |
| + | |
| + | Чаще всего этот оператор используется, когда тип объекта вообще не определен. В этом случае компилятор проверяет только то, что хотя бы один объектный тип во всем дереве имеет указанную переменную или процедуру. Эту технику следует использовать не из лени, а когда у вас есть законные причины оставить тип объекта неопределенным. Например, если переменная может содержать ссылки на объекты типов, не имеющих общего предка (например, obj и mob). Однако в большинстве случаев лучше использовать возможности компилятора по проверке типов. |
| + | |
| + | Следующие ''verb'' демонстрируют два способа расширить вышеупомянутую команду summon, чтобы она могла принимать в качестве аргументов как мобов, так и объекты. |
| + | |
| + | mob/verb |
| + | summon1(obj/M as obj|mob) |
| + | M.loc = loc |
| + | summon2(M as obj|mob) |
| + | M:loc = loc |
| + | |
| + | Первый пример радует компилятор тем, что он лжет о типе переменной. M может быть obj, но может быть и mob. В любом случае у них обоих есть переменная ''loc'', так что во время выполнения все будет работать. |
| + | |
| + | Во втором случае компилятор остается доволен, используя оператор ":" для нестрогой проверки типов. Поскольку для M не объявлен тип, компилятор просто проверяет, есть ли у какого-то типа объекта переменная ''loc''. Поскольку таких типов несколько (примеры - obj, mob и turf), проверка проходит успешно. |
| + | |
| + | Суть в том, что ни строгий, ни нестрогий оператор не влияют на значение самой переменной. Они просто управляют тем, как компилятор выполняет проверку типов. Во время выполнения все, что имеет значение, - это наличие у объекта запрашиваемой переменной. |
| | | |
| = Оператор пути = | | = Оператор пути = |