使用CLOS类实例作为哈希表键? [英] Using CLOS class instances as hash-table keys?
问题描述
我有以下课程:
(defclass category ()
((cat-channel-name
:accessor cat-channel-name :initarg :cat-channel-name :initform "" :type string
:documentation "Name of the channel of this category")
(cat-min
:accessor cat-min :initarg :min :initform 0 :type number
:documentation "Mininum value of category")
(cat-max
:accessor cat-max :initarg :max :initform 1 :type number
:documentation "Maximum value of category"))
(:documentation "A category"))
现在,我想使用此类作为哈希表的键。实例的地址可以很容易地与 eq
进行比较。但是问题是,该类别
类可能有多个相同的实例,我希望哈希表也将其识别为键。
Now, I would like to use this class as a key for a hash-table. The addresses of instances can be easily compared with eq
. The problem is however, there might be multiple identical instances of this category
class and I would like the hash-table to recognize this as a key as well.
因此,我试图覆盖 make-hash-table $的
:test
参数c $ c>这样的函数:
So, I was trying to overwrite the :test
argument of the make-hash-table
function like this:
(make-hash-table :test #'(lambda (a b) (and (equal (cat-channel-name a) (cat-channel-name b))
(eq (cat-min a) (cat-min b))
(eq (cat-max a) (cat-max b)))
很遗憾,这是不允许的。: test
必须是函数eq,eql,equal或equip的指定者。
Unfortunately, this is not allowed. :test
needs to be a designator for one of the functions eq, eql, equal, or equalp.
一种解决方法是将类 category
转换为结构,但我需要将其作为类。有什么办法可以解决这个问题?
One way to solve this would be to turn the class category
into a struct, but I need it to be a class. Is there any way I can solve this?
推荐答案
您可以使用更具扩展性的哈希t功能强大的库,如coredump的答案所述,但是您也可以使用Common Lisp对符号进行处理的方法:您可以实习。在这种情况下,您只需要一个适当的内部函数即可使用足够多的类别来生成规范实例,并使用一个哈希表来存储它们。例如,使用简化的 category 类:
You can use a more extensible hash table library, as explained in coredump's answer, but you could also use the approach that Common Lisp takes toward symbols: you can intern them. In this case, you just need an appropriate interning function that takes enough of a category to produce a canonical instance, and a hash table to store them. E.g., with a simplified category class:
(defclass category ()
((name :accessor cat-name :initarg :name)
(number :accessor cat-number :initarg :number)))
(defparameter *categories*
(make-hash-table :test 'equalp))
(defun intern-category (name number)
(let ((key (list name number)))
(multiple-value-bind (category presentp)
(gethash key *categories*)
(if presentp category
(setf (gethash key *categories*)
(make-instance 'category
:name name
:number number))))))
然后,您可以用相同的参数调用 intern-category 并获得相同的对象,可以安全地将其用作哈希表键:
Then, you can call intern-category with the same arguments and get the same object back, which you can safely use as a hash table key:
(eq (intern-category "foo" 45)
(intern-category "foo" 45))
;=> T
这篇关于使用CLOS类实例作为哈希表键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!