19.2 Как использовать defstruct

Все структуры определяются с помощью конструкции defstruct. Вызов defstruct определяет новый тип данных, экземпляры которого содержат именованные слоты.

[Макрос] defstruct name-and-options [doc-string] {slot-description}*

Этот макрос определяет структурный тип данных. Обычно вызов defstruct выглядит как следующий пример.

(defstruct (name option-1 option-2 ... option-m)
           doc-string
           slot-description-1
           slot-description-2
           ...
           slot-description-n)

Имя структуры name должно быть символом. Данный символ будет обозначать новый тип данных, который включает в себя все экземпляры данной структуры. Соответственно функция typep будет принимать и использовать это имя. Имя структуры name возвращается как значение формы defstruct.

Обычно параметры не нужны. Если они не заданы, то после слова defstruct вместо (name) можно записать просто name . Синтаксис параметров и их смысл раскрываются в разделе 19.5.

Если присутствует необязательная строка документации doc-string, тогда она присоединяется к символу name, как документация для типа structure. Смотрите documentation.

Каждое описание слота slot-description-j выглядит так:

(slot-name default-init
     slot-option-name-1 slot-option-value-1
     slot-option-name-2 slot-option-value-2
     ...
     slot-option-name-kj slot-option-value-kj)

Каждое имя слота slot-name должно быть символом. Для каждого слота определяется функция доступа. Если параметры и первоначальные значения не указаны, тогда в качестве описания слота вместо (slot-name) можно записать просто slot-name.

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

Если default-init не указано, тогда первоначальное значение слота не определено и зависит от реализации. Доступные параметры для слотов разобраны в разделе 19.4.

Слоты не могут иметь одинаковые имена. Даже если символы для имён из разных пакетов, всё равно нельзя.

Так нельзя:

(defstruct lotsa-slots slot slot)

Так тоже нельзя:

(defstruct no-dice coin:slot blot:slot)

А здесь первую структуру создать можно, а вторую нельзя:

(defstruct one-slot slot)
(defstruct (two-slots (:include one-slot)) slot)

defstruct не только определяет функции доступа к слотам, но также выполняет интеграцию с setf для этих функций, определяет предикат с именем name-p, определяет функцию-конструктор с именем make-name и определяет функцию копирования с именем copy-name. Все имена автоматически создаваемых функций интернируются в текущий пакет на время выполнения defstruct (смотрите *package*). Кроме того, все эти функции могут быть задекларированы как inline на усмотрение реализации для повышения производительности. Если вы не хотите, чтобы функции были задекларированы как inline, укажите декларацию notinline после формы defstruct для перезаписи декларации inline.

При переопределении структуры современные реализации чаще всего генерируют исключение с возможностью применить новое определение, оставить старое, и т.д.