首页 > 解决方案 > LISP--传递一个结构组件,而不是组件的值

问题描述

我在 LISP 中传递结构组件时遇到问题。我想传递组件,而不是组件的值。

为了说明我的目标,假设我有一个结构实例,node. 节点具有组件farmerfoxgoosestraw。我希望函数灵活,所以我可以将这些组件中的任何一个传递给函数。

(defun pass-comp (node object)
  (setf object 1)
  node)

(pass-comp (node (node-fox node))
(write (node-fox node))
—> 1

标签: lispcommon-lisp

解决方案


在 Lisp 中,所有参数总是按值传递。如果要修改传递的结构的内容,可以通过指定要修改的内容来完成:

(defstruct node farmer fox goose straw)
(defparameter *node* (make-node :fox 3))
(defun change-slot (object slot-name new-value)
  (setf (slot-value object slot-name) new-value))
(change-slot *node* 'fox 7)
(change-slot *node* 'goose 23)
*node*
==> #S(NODE :FARMER NIL :FOX 3 :GOOSE 23 :STRAW NIL)

请注意,即使该标准不需要slot-value在 上运行 , structure-object上面的代码也适用于所有 CL 实现。

如果您希望您的代码符合要求,则应传递一个setter

(defun change-slot (object setter new-value)
  (funcall setter new-value object))
(change-slot *node* #'(setf node-farmer) 6)
*node*
==> #S(NODE :FARMER 6 :FOX 3 :GOOSE 23 :STRAW NIL)

唉,这也不能保证工作,因为

写入槽的能力是由 setf 函数还是由 setf 扩展器实现的,这取决于实现。

因此,您需要创建自己的 setter:

(change-slot *node* (lambda (straw node) (setf (node-straw node) straw)) 11)
*node*
==> #S(NODE :FARMER 6 :FOX 3 :GOOSE 23 :STRAW 11)

推荐阅读