LISP - `:before` 方法组合
Lisp - :before 方法组合
Section titled “Lisp - :before 方法组合”在 Common Lisp 对象系统(CLOS)中,方法组合(method combination)控制着单个泛型函数(generic function)的不同方法(method)如何组合与执行。标准方法组合提供了几种辅助方法类型,包括 :before 方法。:before 方法是一个强大工具,用于在主方法(primary method)被调用之前执行代码。
:before 方法的常见用例包括:
- 输入验证:在主逻辑运行前检查参数。
- 设置:确保前置条件或状态已正确建立。
- 日志记录和追踪:为调试打印消息或追踪方法调用。
- 预备计算:执行计算,并将结果存储起来供后续使用(例如,存储在 slot 中)。
定义 :before 方法
Section titled “定义 :before 方法”你使用 defmethod 定义 :before 方法,其中 :before 限定符位于泛型函数名称和参数列表之间。至关重要的是,:before 方法的返回值总是被忽略的。
;; 1. Define a generic function.(defgeneric process-data (data))
;; 2. Define a :before method that applies to ALL types of data (specialized on T).(defmethod process-data :before ((data t)) (format t "[LOG] Preparing to process data: ~a~%" data))
;; 3. Define a more specific :before method just for integers.(defmethod process-data :before ((data integer)) (format t "[VALIDATE] Integer-specific check for ~a passed.~%" data))执行顺序和示例
Section titled “执行顺序和示例”当一个泛型函数被调用时,CLOS 首先会以从最具体到最通用的顺序执行所有适用的 :before 方法。所有 :before 方法运行完毕后,单个最具体的主方法(primary method)才会被执行。
;;; --- Generic Function Definition ---(defgeneric process-data (data))
;;; --- :before Methods (for setup and logging) ---;; Most-general :before method(defmethod process-data :before ((data t)) (format t "Preparing to process data: ~a~%" data))
;; More-specific :before method for integers(defmethod process-data :before ((data integer)) (format t "Integer-specific preparation for: ~a~%" data))
;;; --- Primary Methods (for the main logic) ---;; Primary method for integers(defmethod process-data ((data integer)) (format t "--> Processing integer: ~a, result: ~a~%" data (* data 2)))
;; Primary method for strings(defmethod process-data ((data string)) (format t "--> Processing string: ~a, result: ~a~%" data (concatenate 'string data "-processed")))
;;; --- Calling the Generic Function ---(print "--- Calling with an integer ---")(process-data 10)
(print "--- Calling with a string ---")(process-data "test")当你执行这段代码时,方法会按照特定顺序组合并调用:
"--- Calling with an integer ---"Integer-specific preparation for: 10Preparing to process data: 10--> Processing integer: 10, result: 20
"--- Calling with a string ---"Preparing to process data: "test"--> Processing string: "test", result: "test-processed"- 当 (process-data 10) 被调用时:
-
- 最具体的 :before 方法 ((data integer)) 首先运行。
-
- 接着运行不太具体的 :before 方法 ((data t))。
-
- 最后,最具体的主方法 ((data integer)) 运行。
- 当 (process-data “test”) 被调用时:
-
- 只有一个 :before 方法适用 ((data t)),因此它运行。
-
- 最具体的主方法 ((data string)) 运行。
常见陷阱和最佳实践
Section titled “常见陷阱和最佳实践”- 常见错误:尝试从 :before 方法返回一个值以停止执行或改变主方法的参数。这是行不通的。它们的返回值会被丢弃。要达到这种程度的控制,你必须使用 :around 方法。
- 最佳实践:保持 :before 方法简单,并专注于单一任务,例如验证或日志记录。它们不应包含复杂的应用逻辑。它们旨在为主方法做准备,而不是执行主方法的工作。