19.3 Использование автоматически определяемого конструктора

После того, как вы определили новую структуру с помощью defstruct, вы можете создавать экземпляры данной структуры с помощью функции-конструктора. По-умолчанию defstruct сам автоматически определяет эту функцию. Для структуры с именем foo, функция-конструктор обычно называется make-foo. Вы можете указать другое имя, передав его в качестве аргумента для параметра :constructor, или, если вы вообще не хотите обычную функцию-конструктор, указав в качества аргумента nil. В последнем случае должны быть запрошены один или более конструкторов с «позиционными» аргументами, смотрите раздел 19.6.

Общая форма вызова функции-конструктора выглядит так:

(name-of-constructor-function
        slot-keyword-1 form-1
        slot-keyword-2 form-2
        ...)

Все аргументы являются именованными. Каждый slot-keyword должен быть ключевым символом, имя которого совпадает со именем слота структуры (defstruct определяет возможные ключевые символы интернируя каждое имя слота в пакет ключевых символов (keyword). Все ключевые символы keywords и формы forms вычисляются. В целом, это выглядит как если функция-конструктор принимает все аргументы как &key параметры. Например, структура ship упомянутая ранее в разделе 19.1 имеет функцию-конструктор, которая принимает аргументы в соотвествие со следующим определением:

(defun make-ship (&key x-position y-position
                       x-velocity y-velocity mass)
  ...)

Если slot-keyword-j задаёт имя слота, тогда элемент созданной структуры будет инициализирован значением form-j. Если пара slot-keyword-j и form-j для слота не указана, тогда слот будет инициализирован результатом вычисления указанной в вызове defstruct для этого слота формой default-init. (Другими словами, инициализация указанная в defstruct замещается инициализацией указанной в вызове функции-конструктора.) Если используется форма инициализации default-init, она вычисляется в время создания экземпляра структуры, но в лексическом окружении формы defstruct, в которой она используется. Если эта форма инициализации не указана, первоначальное значение слота не определено. Если вам необходимо инициализировать слоты некоторыми значениями, вы должны всегда указывать первоначальное значение или в defstruct, или в вызове функции-конструктора.

Каждая форма инициализации, указанная в компоненте формы defstruct, когда используется функцией-конструктором, перевычисляется при каждом вызове функции. Это, как если бы формы инициализации использовались как формы init для именованных параметров функции-конструктора. Например, если форма (gensym) используется как форма инициализации или в вызове функции-конструктора, или форме инициализации слота в форме defstruct, тогда каждый вызов функции-конструктора вызывал бы gensym для создания нового символа.