使用可变数据作为Common Lisp中的哈希表键?

时间:2018-11-18 16:23:22

标签: common-lisp

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中处理可变哈希表键时,应该知道什么?这是要避免的事情吗?

1 个答案:

答案 0 :(得分:4)

请参见18.1.2 Modifying Hash Table Keys

  

如果存在某些对象(或潜在对象)与修改前的对象等效但之后不再等效的对象,则对对象进行等效性测试明显地修改。 / p>      

如果将对象O1用作哈希表H中的键,然后根据H的等效性测试对其进行了明显修改,则如果{ {1}}或在等效性测试下(修改之前或之后)等效于O1的任何对象O2被用作对O1进行进一步操作的键。即使H进行了明显的修改,然后又以撤消可见修改的方式再次修改,仍未指定使用O1作为键的后果。

在您的示例中,hash table testeql,表示修改 键(将元素添加到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*

最重要的是:不要 明显修改哈希表键!