LISP - 槽位与访问器
Lisp - 类、槽和访问器
Section titled “Lisp - 类、槽和访问器”欢迎来到 Common Lisp 对象系统 (CLOS),这是现有的最强大和灵活的对象系统之一。在本章中,我们将学习基础知识:定义类、容纳其数据的槽位以及用于与数据交互的访问器。
使用 defclass 定义类
Section titled “使用 defclass 定义类”类是创建对象的蓝图。我们使用 defclass 宏定义一个类。在其中,我们定义槽位,它们是类的数据成员。让我们为电商应用程序建模一个 product。
(defclass product () ((id :initarg :id :reader product-id) (name :initarg :name :accessor product-name) (price :initarg :price :accessor product-price :initform 0.0 :type 'float) (inventory-count :initarg :inventory :accessor product-inventory :initform 0 :type 'integer)))理解槽位选项
Section titled “理解槽位选项”每个槽位都通过一个名称和控制其行为的选项来定义:
:initarg:创建一个关键字(例如:id),用于在使用make-instance创建对象时初始化此槽位。:accessor:创建一个泛型函数(例如product-name),可以使用(setf (product-name an-instance) new-value)读取槽位的值并写入槽位。:reader:创建一个只能读取槽位值的函数(例如product-id)。这对于像 ID 这样的不可变字段很有用。:writer:(上面未用到)创建一个只能写入槽位的函数。它不如:accessor或:reader常见。:initform:如果初始化时未提供槽位的值,则为其提供默认值(例如,price默认为0.0)。:type:指定槽位预期的数据类型。这有助于错误检查和潜在的编译器优化。
创建和使用对象
Section titled “创建和使用对象”我们使用 make-instance 创建一个类的实例。然后,我们使用定义的访问器和读取器函数来与其数据交互。
完整示例(main.lisp)
Section titled “完整示例(main.lisp)”;; 如上所示定义 'product' 类
;; --- 创建类的实例 ---(defvar *keyboard* (make-instance 'product :id "KBD-42" :name "Mechanical Keyboard" :price 99.99 :inventory 50))
;; --- 使用访问器和读取器读取数据 ---(format t "--- Initial Product State ---~%")(format t "ID: ~a (read-only)~%" (product-id *keyboard*))(format t "Name: ~a~%" (product-name *keyboard*))(format t "Price: $~,2f~%" (product-price *keyboard*))(format t "In Stock: ~d~%~%" (product-inventory *keyboard*))
;; --- 使用访问器更新数据 ---(format t "--- Updating Product State ---~%")(format t "Putting the keyboard on sale...~%")(setf (product-price *keyboard*) 79.99)
;; 顾客购买了一个(decf (product-inventory *keyboard*))
;; --- 显示更新后的状态 ---(format t "New Price: $~,2f~%" (product-price *keyboard*))(format t "New Stock: ~d~%" (product-inventory *keyboard*))
;; --- 尝试写入只读槽位将导致错误 ---; (setf (product-id *keyboard*) "NEW-ID") ; 这将引发错误执行代码后,将返回以下结果:
--- Initial Product State ---ID: KBD-42 (read-only)Name: Mechanical KeyboardPrice: $99.99In Stock: 50
--- Updating Product State ---Putting the keyboard on sale...New Price: $79.99New Stock: 49主要收获和下一步
Section titled “主要收获和下一步”- 封装:对不可变数据使用
:reader,对可变数据使用:accessor是封装的关键部分,可以保护对象免受无效状态更改。 make-instance:这是所有 CLOS 对象的通用构造函数。关键字参数的使用使得初始化代码可读且自文档化。- CLOS 的强大之处:这仅仅是开始。CLOS 的真正强大之处来自于泛型函数和
defmethod,它们允许你为不同的类定义专门的行为,从而实现真正的多态性。例如,你可以定义一个通用的ship-item函数,使其对physical-product和digital-download表现不同。