lisp - 使用 SETF 函数扩展 SETF 是如何工作的?

标签 lisp common-lisp setf

Practical Common Lisp 章节中 17. Object Reorientation: Classes Accessor Functions 部分,我发现很难理解 SETF 的扩展方式。

功能:

(defun (setf customer-name) (name account)
  (setf (slot-value account 'customer-name) name))

bank-account类定义:

(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 bank-account 类的 slot-value customer-name 然后 SETF 用来将值设置为“Sally Sue”?

  • (setf (customer-name my-account) "Sally Sue") 是否实际调用了上面的函数?

  • 上面定义的setf customer-name是一个函数吗?

  • 在上面的函数中是(setf customer-name)中的customer-name和body中的'customer-name指的是同一件事吗?

  • 章节状态

    second element is a symbol, typically the name of a function used to access the place the SETF function will set

    如果是这样,那么当函数可用于访问该位置时,为什么还要在函数定义中使用 slot-value 函数?

最佳答案

在很多情况下访问和设置数据,需要做两件事:

  • 一种从数据结构中检索内容的方法
  • 一种在数据结构中设置内容的方法

因此可以定义一个 setter 函数和一个 getter 函数。对于简单的情况,它们也可能看起来很简单。但对于复杂的情况,他们可能不会。现在如果你知道 getter 的名字,那么 setter 的名字是什么?或者:如果知道 setter 的名称,那么 getter 的名称是什么?

Common Lisp 认为您只需要知道 getter 的名称即可。

  • getter 被称为 GET-FOO

  • 然后调用 setter 函数 (SETF GET-FOO)。总是。

  • setter 函数可以这样调用:(setf (get-foo some-bar) new-foo)。总是。

因此您编写了 GET-FOO 函数。您还编写了 (SETF GET-FOO) 函数,Common Lisp 将其注册为 setter 函数。

(SETF GET-FOO) 是一个列表。它也是一个函数的名称。这里有一个异常(exception):Common Lisp 有时允许将列表作为函数名。因此,并非所有函数名称都是符号,有些实际上是列表。

(setf (customer-name my-account) "Sally Sue") 实际上是调用定义的setter。 my-account 是一个变量,其值将绑定(bind)到 setter 的 account 变量。 "Sally Sue" 是一个字符串,它将绑定(bind)到 setter 的 name 变量。

作为开发人员,您只需了解 getter:

  • getter 的使用:(customer-name my-account)

  • setter 的使用:(setf (customer-name my-account) "Sally Sue")SETF 是一个宏,它扩展为对 setter 函数的调用。

(defun (setf customer-name) (name account)
  (setf (slot-value account 'customer-name) name))

上面定义了一个名为 (setf customer-name) 的 setter 函数。

CL-USER 80 > (function (setf customer-name))
#<interpreted function (SETF CUSTOMER-NAME) 40A00213FC>

当通过 SETF 宏调用该函数时,它会调用另一个 setter - 这次使用通过槽名称访问槽值。

关于lisp - 使用 SETF 函数扩展 SETF 是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24090571/

相关文章:

lisp - Scheme(plt-scheme)中关于 "If.."

function - Common Lisp中#'callee and '被调用者之间的区别

lisp - 编写一个函数 COUNT-NUMBERS 来计算列表中数字的数量

c++ - 防止在C++中显示小数点前的零

oop - 为什么泛型函数与访问函数 lisp 不同

lisp - lisp中循环列表的长度

compiler-errors - 从CLISP界面运行Common Lisp文件(错误)

math - LISP 中的向量计算

list - 如何在递归置换函数中一个一个地返回置换列表元素?

common-lisp - 定义setf函数时如何实现递归?