1

从我读过的东西中,我了解到 CLOS 中的访问器函数允许程序员获取和设置变量,它会生成一个通用函数,该函数的名称是提供给访问器的,您需要定义不同的方法。但我是什么我想知道为什么泛型函数的工作方式与访问器函数不同?

例如

 (defclass animal ()
       ((sound
         :initarg :sound
         :initform "no sound"
         :accessor make-sound)))

我可以定义

(defmethod (setf make-sound) ((the-animal animal) value)
       (setf (slot-value the-animal 'sound) value))

但是如果我要拿走访问器并添加

(defgeneric (setf make-sound) (the-animal value))

然后在执行以下代码后出现错误。

(setf (make-sound dog) "bark")

除非我将通用函数和方法重新定义如下

(defgeneric (setf make-sound) (value the-animal))

 (defmethod (setf make-sound) (value (the-animal animal))
   (setf (slot-value the-animal 'sound) value))

或执行

(setf (make-sound "bark") dog) ;this also works with the accessor

我的问题是为什么会发生这种情况?为什么我不能用泛型函数达到相同的结果?

4

1 回答 1

4

如果没有,defmethod表单会创建一个通用函数

CL-USER 7 > (defclass animal ()
              ((sound
                :initarg :sound
                :initform "no sound")))
#<STANDARD-CLASS ANIMAL 40200ED09B>

Remember: the new value comes first in a SETF function. That's defined by the Common Lisp standard.

CL-USER 8 > (defmethod (setf make-sound) (value (the-animal animal))
              (setf (slot-value the-animal 'sound) value))
#<STANDARD-METHOD (SETF MAKE-SOUND) NIL (T ANIMAL) 40200F098B>

CL-USER 9 > (let ((dog (make-instance 'animal)))
              (setf (make-sound dog) "bark")
              dog)
#<ANIMAL 402002187B>

CL-USER 10 > (slot-value * 'sound)
"bark"

Seems to work.

In defclass the :accessor slot option defines that it defines a reader method and also a corresponding setf method with the correct parameter list: new value first, then the instance of that class.

于 2018-07-27T17:03:39.120 回答