4

下面的代码做我想要的:

 1 (defclass some-class ()
 2   ((some-slot
 3       :initarg :somearg
 4       :initform (error ":somearg not specified"))))
 5 (defparameter *alpha* (make-instance 'some-class :somearg 3))
 6 (defparameter *beta*  (make-instance 'some-class :somearg 5))
 7 (defparameter *gamma* (make-instance 'some-class :somearg 3))
 8 (princ (slot-value *beta* 'some-slot)) (terpri)
 9 (defparameter *delta* (list *alpha* *beta* *gamma*))
10 (princ *delta*) (terpri)
11 (princ (remove-duplicates *delta*
12          :test #'equal
13          :key (lambda (x) (slot-value x 'some-slot))))
14 (terpri)
5
(#<SOME-CLASS #x21C1D71E> #<SOME-CLASS #x21C1DAFE> #<SOME-CLASS #x21C1DC3E>)
(#<SOME-CLASS #x21C1DAFE> #<SOME-CLASS #x21C1DC3E>)

但是有没有办法做到这一点而不必在第 13 行编写函数?是否有一种速记方法可以将类实例中的插槽值指定为键?

当然,以下内容会出现语法错误,但它给出了我正在寻找的大致概念。

 1 (princ (remove-duplicates *delta*
 2          :test #'equal
 3          :key '(slot-value 'some-slot)))
 4 (terpri)
*** - FUNCALL: (SLOT-VALUE 'SOME-SLOT) is not a function name; try using a
      symbol instead
4

2 回答 2

3

你可以试试:readeror :accessor

正在做

(defclass some-class ()
  ((some-slot
    :initarg :somearg :reader some-slot
    :initform (error ":somearg not specified"))))

应该让您将第 11 行到第 13 行重写为

(princ (remove-duplicates *delta* :test #'equal :key #'some-slot))

也就是说,(some-slot x)等效于(slot-value x 'some-slot)所讨论的插槽是否具有读取器/访问器。


睡后编辑:

您也无需费心设置:initform错误;如果您未指定默认值并且有人尝试读取它,则默认情况下插槽将执行此操作。如果您希望出现错误,请执行类似:initform nil. 查看这个出色的CLOS 教程以及Practical Common Lisp 的第 16 章和第 17 章,了解有关 Common Lisp 中对象的更多信息。

此外,将来如果您有想要样式建议的工作代码,请查看codereview.stackexchange。Lisp 审阅者人数虽少,但活跃。

于 2012-01-29T06:14:01.523 回答
2

您可以为 中的插槽定义一个阅读器功能,defclass并将其作为键功能提供给remove-duplicates. 例如,将此行添加到插槽定义中:

:reader some-slot

然后在调用中使用它remove-duplicates

:key #'some-slot
于 2012-01-29T06:17:59.123 回答