Lisp中when语句内调用make-instance创建Thing实例报错排查
解决Common Lisp中
make-instance在方法内创建实例时的槽未绑定错误 问题现象
在SBCL和CLISP环境运行代码时,触发错误:The slot COMMON-LISP-USER::NAME is unbound in the object #<THING {1002B830F3}>。手动创建名为"ash"的Thing实例可成功,但在burn方法的when条件块内调用make-instance创建该实例时失败。
问题原因
错误根源在Thing类的initialize-instance :around方法中:调用call-next-method时,错误地将实例obj作为第一个参数传入。call-next-method在:around方法中会自动使用当前实例和原始参数(除非显式指定),额外传入的obj会被当作初始化参数的一部分,导致:name参数被错位处理,最终实例的name槽未被正确绑定。
修复方案
修改initialize-instance :around方法,移除call-next-method的第一个obj参数,直接将过滤后的初始化参数传递给call-next-method即可。
修复后的完整代码
(defclass thing () ((name :initarg :name :accessor thing-name) (properties :initform nil :accessor thing-properties))) (defmethod initialize-instance :around ((obj thing) &rest initargs &key &allow-other-keys) (let* ((class (class-of obj))) (apply #'call-next-method ; 移除多余的obj参数 (loop for (key val) on initargs by #'cddr when (member key '(name properties)) ; 仅允许指定的参数 append (list key val))))) (defclass process () ((name :initarg :name :accessor process-name))) (defmethod burn ((proc process) (chair thing) (oxygen thing)) (declare (ignore proc)) (when (and (string= (thing-name chair) "chair") (string= (thing-name oxygen) "oxygen")) (make-instance 'thing :name "ash"))) ;; 测试代码 (defparameter *chair* (make-instance 'thing :name "chair")) (defparameter *oxygen* (make-instance 'thing :name "oxygen")) (defparameter *burning* (make-instance 'process :name "burning")) ;; 执行燃烧操作 (defparameter *result* (burn *burning* *chair* *oxygen*)) ;; 调试输出 (format t "Result: ~A" *result*) ; 成功时会输出创建的"ash"实例
修复说明
修改后的initialize-instance :around方法会正确过滤初始化参数,并将其传递给默认的initialize-instance实现,确保:name参数被正常解析并绑定到实例槽中。无论手动创建实例还是在burn方法内部创建,都能完成正确的初始化。
内容的提问来源于stack exchange,提问作者nadirkazan
相关产品推荐
相关产品推荐

