《通链参考手册》


Macro DEFSTRUCT

●语法设定:

defstruct name-and-options [documentation] {slot-description}*

=> structure-name

name-and-options::= structure-name | (structure-name [[options]]) 
options::= conc-name-option | 
           {constructor-option}* | 
           copier-option | 
           include-option | 
           initial-offset-option | 
           named-option | 
           predicate-option | 
           printer-option | 
           type-option 
conc-name-option::= :conc-name | (:conc-name) | (:conc-name conc-name) 
constructor-option::= :constructor | 
                      (:constructor) | 
                      (:constructor constructor-name) | 
                      (:constructor constructor-name constructor-arglist) 
copier-option::= :copier | (:copier) | (:copier copier-name) 
predicate-option::= :predicate | (:predicate) | (:predicate predicate-name) 
include-option::= (:include included-structure-name {slot-description}*) 
printer-option::= print-object-option | print-function-option 
print-object-option::= (:print-object printer-name) | (:print-object) 
print-function-option::= (:print-function printer-name) | (:print-function) 
type-option::= (:type type) 
named-option::= :named 
initial-offset-option::= (:initial-offset initial-offset) 
slot-description::= slot-name |  
                    (slot-name [slot-initform [[slot-option]]]) 
slot-option::= :type slot-type |  
               :read-only slot-read-only-p 

●参数和值:

conc-name---a string designator.

constructor-arglist---a boa lambda list.

constructor-name---a symbol.

copier-name---a symbol.

included-structure-name---an already-defined structure name. Note that a derived type is not permissible, even if it would expand into a structure name.

initial-offset---a non-negative integer.

predicate-name---a symbol.

printer-name---a function name or a lambda expression.

slot-name---a symbol.

slot-initform---a form.

slot-read-only-p---a generalized boolean.

structure-name---a symbol.

type---one of the type specifiers list, vector, or (vector size), or some other type specifier defined by the implementation to be appropriate.

documentation---a string; not evaluated.

●详情:

defstruct defines a structured type, named structure-type, with named slots as specified by the slot-options.

defstruct defines readers for the slots and arranges for setf to work properly on such reader functions. Also, unless overridden, it defines a predicate named name-p, defines a constructor function named make-constructor-name, and defines a copier function named copy-constructor-name. All names of automatically created functions might automatically be declared inline (at the discretion of the implementation).

If documentation is supplied, it is attached to structure-name as a documentation string of kind structure, and unless :type is used, the documentation is also attached to structure-name as a documentation string of kind type and as a documentation string to the class object for the class named structure-name.

defstruct defines a constructor function that is used to create instances of the structure created by defstruct. The default name is make-structure-name. A different name can be supplied by giving the name as the argument to the constructor option. nil indicates that no constructor function will be created.

After a new structure type has been defined, instances of that type normally can be created by using the constructor function for the type. A call to a constructor function is of the following form:

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

The arguments to the constructor function are all keyword arguments. Each slot keyword argument must be a keyword whose name corresponds to the name of a structure slot. All the keywords and forms are evaluated. If a slot is not initialized in this way, it is initialized by evaluating slot-initform in the slot description at the time the constructor function is called. If no slot-initform is supplied, the consequences are undefined if an attempt is later made to read the slot's value before a value is explicitly assigned.

Each slot-initform supplied for a defstruct component, when used by the constructor function for an otherwise unsupplied component, is re-evaluated on every call to the constructor function. The slot-initform is not evaluated unless it is needed in the creation of a particular structure instance. If it is never needed, there can be no type-mismatch error, even if the type of the slot is specified; no warning should be issued in this case. For example, in the following sequence, only the last call is an error.

 (defstruct person (name 007 :type string)) 
 (make-person :name "James")
 (make-person)

It is as if the slot-initforms were used as initialization forms for the keyword parameters of the constructor function.

The symbols which name the slots must not be used by the implementation as the names for the lambda variables in the constructor function, since one or more of those symbols might have been proclaimed special or might be defined as the name of a constant variable. The slot default init forms are evaluated in the lexical environment in which the defstruct form itself appears and in the dynamic environment in which the call to the constructor function appears.

For example, if the form (gensym) were used as an initialization form, either in the constructor-function call or as the default initialization form in defstruct, then every call to the constructor function would call gensym once to generate a new symbol.

Each slot-description in defstruct can specify zero or more slot-options. A slot-option consists of a pair of a keyword and a value (which is not a form to be evaluated, but the value itself). For example:

 (defstruct ship
   (x-position 0.0 :type short-float)
   (y-position 0.0 :type short-float)
   (x-velocity 0.0 :type short-float)
   (y-velocity 0.0 :type short-float)
   (mass *default-ship-mass* :type short-float :read-only t))
This specifies that each slot always contains a short float, and that the last slot cannot be altered once a ship is constructed.

The available slot-options are:

The following keyword options are available for use with defstruct. A defstruct option can be either a keyword or a list of a keyword and arguments for that keyword; specifying the keyword by itself is equivalent to specifying a list consisting of the keyword and no arguments. The syntax for defstruct options differs from the pair syntax used for slot-options. No part of any of these options is evaluated.

The consequences of redefining a defstruct structure are undefined.

In the case where no defstruct options have been supplied, the following functions are automatically defined to operate on instances of the new structure:

If a defstruct form appears as a top level form, the compiler must make the structure type name recognized as a valid type name in subsequent declarations (as for deftype) and make the structure slot readers known to setf. In addition, the compiler must save enough information about the structure type so that further defstruct definitions can use :include in a subsequent deftype in the same file to refer to the structure type name. The functions which defstruct generates are not defined in the compile time environment, although the compiler may save enough information about the functions to code subsequent calls inline. The #S reader macro might or might not recognize the newly defined structure type name at compile time.

●例子:

An example of a structure definition follows:

 (defstruct ship
   x-position
   y-position
   x-velocity
   y-velocity
   mass)
This declares that every ship is an object with five named components. The evaluation of this form does the following:

  1. It defines ship-x-position to be a function of one argument, a ship, that returns the x-position of the ship; ship-y-position and the other components are given similar function definitions. These functions are called the access functions, as they are used to access elements of the structure.

  2. ship becomes the name of a type of which instances of ships are elements. ship becomes acceptable to typep, for example; (typep x 'ship) is true if x is a ship and false if x is any object other than a ship.

  3. A function named ship-p of one argument is defined; it is a predicate that is true if its argument is a ship and is false otherwise.

  4. A function called make-ship is defined that, when invoked, creates a data structure with five components, suitable for use with the access functions. Thus executing

     (setq ship2 (make-ship))
    
    sets ship2 to a newly created ship object. One can supply the initial values of any desired component in the call to make-ship by using keyword arguments in this way:

     (setq ship2 (make-ship :mass *default-ship-mass*
                            :x-position 0
                            :y-position 0))
    
    This constructs a new ship and initializes three of its components. This function is called the ``constructor function'' because it constructs a new structure.

  5. A function called copy-ship of one argument is defined that, when given a ship object, creates a new ship object that is a copy of the given one. This function is called the ``copier function.''

setf can be used to alter the components of a ship:

 (setf (ship-x-position ship2) 100)
This alters the x-position of ship2 to be 100. This works because defstruct behaves as if it generates an appropriate defsetf for each access function.

;;;
;;; Example 1
;;; define town structure type
;;; area, watertowers, firetrucks, population, elevation are its components
;;;
 (defstruct town
             area
             watertowers
             (firetrucks 1 :type fixnum)    ;an initialized slot
             population 
             (elevation 5128 :read-only t)) ;a slot that can't be changed
=>  TOWN
;create a town instance
 (setq town1 (make-town :area 0 :watertowers 0)) =>  #S(TOWN...)
;town's predicate recognizes the new instance
 (town-p town1) =>  true
;new town's area is as specified by make-town
 (town-area town1) =>  0
;new town's elevation has initial value
 (town-elevation town1) =>  5128
;setf recognizes reader function
 (setf (town-population town1) 99) =>  99
 (town-population town1) =>  99
;copier function makes a copy of town1
 (setq town2 (copy-town town1)) =>  #S(TOWN...)
 (= (town-population town1) (town-population town2))  =>  true
;since elevation is a read-only slot, its value can be set only
;when the structure is created
 (setq town3 (make-town :area 0 :watertowers 3 :elevation 1200))
=>  #S(TOWN...)
;;;
;;; Example 2
;;; define clown structure type
;;; this structure uses a nonstandard prefix
;;;
 (defstruct (clown (:conc-name bozo-))
             (nose-color 'red)         
             frizzy-hair-p polkadots) =>  CLOWN
 (setq funny-clown (make-clown)) =>  #S(CLOWN)
;use non-default reader name
 (bozo-nose-color funny-clown) =>  RED        
 (defstruct (klown (:constructor make-up-klown) ;similar def using other
             (:copier clone-klown)              ;customizing keywords
             (:predicate is-a-bozo-p))
             nose-color frizzy-hair-p polkadots) =>  klown
;custom constructor now exists
 (fboundp 'make-up-klown) =>  true
;;;
;;; Example 3
;;; define a vehicle structure type
;;; then define a truck structure type that includes 
;;; the vehicle structure
;;;
 (defstruct vehicle name year (diesel t :read-only t)) =>  VEHICLE
 (defstruct (truck (:include vehicle (year 79)))
             load-limit                          
             (axles 6)) =>  TRUCK
 (setq x (make-truck :name 'mac :diesel t :load-limit 17))
=>  #S(TRUCK...)
;vehicle readers work on trucks
 (vehicle-name x)
=>  MAC
;default taken from :include clause 
 (vehicle-year x)
=>  79 
 (defstruct (pickup (:include truck))     ;pickup type includes truck
             camper long-bed four-wheel-drive) =>  PICKUP
 (setq x (make-pickup :name 'king :long-bed t)) =>  #S(PICKUP...)
;:include default inherited
 (pickup-year x) =>  79
;;;
;;; Example 4
;;; use of BOA constructors
;;;
 (defstruct (dfs-boa                      ;BOA constructors
               (:constructor make-dfs-boa (a b c)) 
               (:constructor create-dfs-boa
                 (a &optional b (c 'cc) &rest d &aux e (f 'ff))))
             a b c d e f) =>  DFS-BOA
;a, b, and c set by position, and the rest are uninitialized
 (setq x (make-dfs-boa 1 2 3)) =>  #(DFS-BOA...)
 (dfs-boa-a x) =>  1
;a and b set, c and f defaulted
 (setq x (create-dfs-boa 1 2)) =>  #(DFS-BOA...)
 (dfs-boa-b x) =>  2
 (eq (dfs-boa-c x) 'cc) =>  true
;a, b, and c set, and the rest are collected into d
 (setq x (create-dfs-boa 1 2 3 4 5 6)) =>  #(DFS-BOA...)
 (dfs-boa-d x) =>  (4 5 6)

●受制于: 无。

●例外情况:

If any two slot names (whether present directly or inherited by the :include option) are the same under string=, defstruct should signal an error of type program-error.

The consequences are undefined if the included-structure-name does not name a structure type.

●更多信息:

documentation, print-object, setf, subtypep, type-of, typep, Section 3.2 (Compilation)

●说明:

The printer-name should observe the values of such printer-control variables as *print-escape*.

The restriction against issuing a warning for type mismatches between a slot-initform and the corresponding slot's :type option is necessary because a slot-initform must be specified in order to specify slot options; in some cases, no suitable default may exist.

The mechanism by which defstruct arranges for slot accessors to be usable with setf is implementation-dependent; for example, it may use setf functions, setf expanders, or some other implementation-dependent mechanism known to that implementation's code for setf.


X3J13设计清单非标准部分,可查下面章节:


◇首页 § ◎章节目录 § □内容索引 § ○符号索引 § △术语表 § ※设计草案