Lisp 如何使用SETF函数来扩展SETF?
在实用的公共Lisp章节部分访问器函数中,我发现很难理解Lisp 如何使用SETF函数来扩展SETF?,lisp,common-lisp,setf,Lisp,Common Lisp,Setf,在实用的公共Lisp章节部分访问器函数中,我发现很难理解SETF的扩展方式 职能: (defun (setf customer-name) (name account) (setf (slot-value account 'customer-name) name)) 银行账户类别定义: (defclass bank-account () ((customer-name :initarg :customer-name :initform (error "Must supp
SETF
的扩展方式
职能:
(defun (setf customer-name) (name account)
(setf (slot-value account 'customer-name) name))
银行账户
类别定义:
(defclass bank-account ()
((customer-name
:initarg :customer-name
:initform (error "Must supply a customer name."))
(balance
:initarg :balance
:initform 0)
(account-number
:initform (incf *account-numbers*))
account-type))
我不明白的是:
- 在表达式
中,是否(setf(customer name my account)“Sally Sue”)
返回类(customer name my account)
银行帐户的一个SETFable slot值
,然后customer name
使用该值将该值设置为“Sally Sue”setf
是否实际调用了上述函数(setf(customer name my account)“Sally Sue”)
- 如上所述,
a函数setf customer name
- 在上面的函数中,
中的(setf customer name)
,以及主体中的客户名称
,指的是同一事物吗客户名称
- 该节指出
第二个元素是符号,通常是用于访问SETF函数将设置的位置的函数的名称
如果是这种情况,那么当函数可用于访问位置时,为什么要在函数定义中使用
插槽值
函数呢
- 从数据结构中检索内容的一种方法
- 在数据结构中设置某些内容的方法
- getter被调用,比如说,
GET-FOO
- 然后调用setter函数
。总是(SETF GET-FOO)
- setter函数可以这样调用:
。总是(setf(getfoosomebar)newfoo)
GET-FOO
函数。您还编写了(SETF GET-FOO)
函数,Common Lisp将其注册为setter函数
(SETF GET-FOO)
是一个列表。它也是一个函数的名称。这里我们有一个例外:CommonLisp有时允许将列表作为函数名。因此,并非所有函数名都是符号,有些实际上是列表
(setf(customer name my account)“Sally Sue”)
实际上是对已定义setter的调用my account
是一个变量,其值将绑定到setter的account
变量“Sally Sue”
是一个字符串,它将绑定到setter的name
变量
作为一名开发人员,您只需了解getter:
- getter的使用:
(客户名称我的帐户)
- setter的使用:
(setf(客户名称我的帐户)“Sally Sue”)
是一个宏,它扩展为对setter函数的调用SETF
(setf customer name)
的setter函数
CL-USER 80>(功能(setf客户名称))
#
当函数通过
SETF
宏调用时,它会调用另一个setter——这次是通过插槽名称访问插槽值。SETF
是一个非常复杂的宏,它知道如何将其第一个参数(通常看起来像函数调用)解码为“位置”然后调用将位置设置为新值所需的任何形式。将(客户名称我的帐户)
视为在setf
表达式中返回任何内容是没有用的。setf
宏将在中定义的规则应用于其位置表单,并且作为默认情况,将转换
(setf (foo arg0 arg1 ...) new-val)
到
实用公共Lisp中的这段话以一种略带椭圆的方式解释了当您在
defclass
插槽定义中指定:accessor
选项时,在幕后会发生什么。So(setf(customer name my account)“Sally Sue”)
调用(setf customer name)
?但该函数需要两个参数,并且只传递一个参数,“Sally Sue”
。@BleedingFingers,(setf customer name)
是您的setter函数。它的名称不仅仅是一个符号,而是一个列表,所以它并不明显,但是当您键入(setf(customer name my account)“Sally Sue”)
时,您调用setter并传递两个参数:string“Sally Sue”和bank account
类的对象。这个特定行为是在哪里定义的?如果帐户
是(setf customer name)
的第一个参数,而帐户
是的第二个参数,那么其工作原理是否相同?(看起来有点像黑魔法。)setf
函数的语义在中定义。新值始终作为第一个参数传递给setf
函数。感谢您的回答。
CL-USER 80 > (function (setf customer-name))
#<interpreted function (SETF CUSTOMER-NAME) 40A00213FC>
(setf (foo arg0 arg1 ...) new-val)
(funcall #'(setf foo) new-val arg0 arg1 ...)