LISP - 结构体选项
Lisp - 使用 defstruct 选项自定义结构体
Section titled “Lisp - 使用 defstruct 选项自定义结构体”The defstruct 宏是创建自定义数据结构的强大工具。除了定义简单的槽位(slot)之外,它还提供了多种选项来控制结构体的行为,例如如何创建、打印和识别它。
The :constructor Option
Section titled “The :constructor Option”默认情况下,defstruct 会创建一个名为 make-<struct-name> 的构造函数。:constructor 选项允许您自定义此行为。
(:constructor): 阻止创建任何构造函数。(:constructor make-my-point): 将构造函数重命名为make-my-point。(:constructor make-point (x y)): 创建一个按位置而非关键字接受参数的构造函数。这对于为小型、常用结构体创建简洁的构造函数很有用。
示例:位置构造函数
Section titled “示例:位置构造函数”;;; 定义一个带有自定义位置构造函数的点结构体(defstruct (point (:constructor make-point (x y))) x y)
;; 使用自定义构造函数创建一个实例(let ((p1 (make-point 10 20))) (format t "Created point with X=~d, Y=~d~%" (point-x p1) (point-y p1)))Created point with X=10, Y=20The :predicate 和 :copier 选项
Section titled “The :predicate 和 :copier 选项”这些选项控制类型检查谓词和结构体复制函数(copier function)的命名。
:predicate: 默认谓词是<struct-name>-p。您可以使用(:predicate is-a-point)重命名它。使用(:predicate)来禁用它。:copier: 默认的复制器是copy-<struct-name>。您可以使用(:copier duplicate-point)重命名它。使用(:copier)来禁用它。
示例:自定义谓词和复制器
Section titled “示例:自定义谓词和复制器”(defstruct (user (:predicate userp) (:copier nil))) name id)
(let ((u1 (make-user :name "Alice" :id 101))) (format t "Is u1 a user? ~a~%" (userp u1)) ;; (copy-user u1) 会导致错误,因为复制器已被禁用。The :print-object 选项
Section titled “The :print-object 选项”The :print-object 选项(:print-function 的一个更现代、更用户友好的替代方案)允许您定义一个自定义函数,用于控制 print、format 等如何显示您的结构体实例。这对于调试和创建可读输出非常宝贵。
示例:自定义打印器
Section titled “示例:自定义打印器”;; 首先,定义负责打印的函数。;; 它必须接受两个参数:对象和输出流。(defun print-custom-point (point stream) (format stream "<Point (~a, ~a)>" (point-x point) (point-y point)))
;; 现在,定义结构体并将其与我们的打印函数关联。(defstruct (point (:constructor make-point (x y)) (:print-object print-custom-point)) x y)
(let ((p1 (make-point 10 20))) ;; 现在 `print` 和 `format` 将自动使用我们的自定义函数。 (format t "The point is: ~a~%" p1))The point is: <Point (10, 20)>用于继承的 :include 选项
Section titled “用于继承的 :include 选项”The :include 选项提供简单的单一继承,允许一个结构体继承另一个结构体的槽位。这是减少代码重复的好方法。
示例:继承槽位
Section titled “示例:继承槽位”;; 基础结构体(defstruct shape (color "black"))
;; Circle 继承自 shape 并添加了半径(defstruct (circle (:include shape)) radius)
(let ((c1 (make-circle :radius 10 :color "red"))) ;; 两个结构体的访问器都有效 (format t "Circle color: ~a, radius: ~a~%" (circle-color c1) (circle-radius c1)) (format t "The circle is: ~s~%" c1))Circle color: red, radius: 10The circle is: #S(CIRCLE :COLOR "red" :RADIUS 10)The :type 选项
Section titled “The :type 选项”默认情况下,结构体可以实现为列表或某些特定于实现的方式。:type 选项允许您强制底层表示为 list 或 vector。这对于性能调优或与其他代码进行接口非常有用。
示例:基于向量的结构体
Section titled “示例:基于向量的结构体”;; 定义一个由向量支持的点结构体(defstruct (vec-point (:type vector)) x y)
(let ((vp1 (make-vec-point :x 5 :y 15))) (format t "Type of vector-point: ~a~%" (type-of vp1)))输出将是一个向量类型,可能如下所示(具体输出可能因实现而异):
Type of vector-point: (SIMPLE-VECTOR 2)结合这些选项可以创建高度专业化和健壮的数据类型。对于涉及多重继承和方法分派的复杂面向对象编程,请考虑使用 Common Lisp 对象系统 (CLOS) 和 defclass,defstruct 就是基于它构建的。