以下代码实现了我想要的功能:
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行写入函数?有没有一种简写的方法可以在类实例中指定一个slot值作为关键字?
当然,下面出现了一个语法错误,但它给出了我所寻求的大致概念。
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
您可以尝试:reader
或: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教程以及实用公共Lisp的第16章和第17章,了解有关公共Lisp中对象的更多信息。
此外,将来如果你有想要风格建议的工作代码,一定要查看codereview.stackeexchange。
您可以为defclass
中的插槽定义一个读取器函数,并将其作为键函数提供给remove-duplicates
。例如,将此行添加到插槽定义中:
:reader some-slot
然后在remove-duplicates
:的调用中使用
:key #'some-slot