Common Lisp似乎允许将可变数据用作哈希表键。
(defparameter *dict* (make-hash-table))
(defparameter *a* (make-hash-table))
(setf (gethash *a* *dict*) 5)
(loop for key being the hash-keys of *dict*
do (progn
(print key)
(print (gethash key *dict*))))
此处将哈希表用作另一个哈希表中的键。
这种行为让我有些困惑。据我了解,如果密钥对象发生突变,则可变的密钥可能会与哈希值混淆。
哈希表如何保持其完整性,更重要的是-在CL中处理可变哈希表键时,应该知道什么?这是要避免的事情吗?
答案 0 :(得分:4)
请参见18.1.2 Modifying Hash Table Keys:
如果存在某些对象(或潜在对象)与修改前的对象等效但之后不再等效的对象,则对对象进行等效性测试明显地修改。 / p>
如果将对象
O1
用作哈希表H
中的键,然后根据H
的等效性测试对其进行了明显修改,则如果{ {1}}或在等效性测试下(修改之前或之后)等效于O1
的任何对象O2
被用作对O1
进行进一步操作的键。即使H
进行了明显的修改,然后又以撤消可见修改的方式再次修改,仍未指定使用O1
作为键的后果。
在您的示例中,hash table test是
eql
,表示修改
键(将元素添加到O1
)不会更改哈希码(即,不是是“可见的修改”):
*a*
因此,您可以看到(defparameter *ht-1* (make-hash-table :test 'eql))
(defparameter *key* (cons nil nil))
(setf (gethash *key* *ht-1*) 10)
*ht-1*
==> #S(HASH-TABLE :TEST FASTHASH-EQL ((NIL) . 10))
(setf (car *key*) 42)
*ht-1*
==> #S(HASH-TABLE :TEST FASTHASH-EQL ((42) . 10))
(gethash *key* *ht-1*)
==> 10; T
(gethash '(42) *ht-1*)
==> NIL; NIL
锁定在特定的对象上,而不是看起来像它的任何东西上。
另一方面,考虑一个equal
哈希表:
*ht-1*
最重要的是:不要 不 明显修改哈希表键!