【问题标题】:Using mutable data as hash table keys in Common Lisp?在 Common Lisp 中使用可变数据作为哈希表键?
【发布时间】:2019-04-21 03:02:29
【问题描述】:

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

【问题讨论】:

    标签: common-lisp


    【解决方案1】:

    18.1.2 Modifying Hash Table Keys:

    如果存在与修改前的对象等价但修改后不再等价的对象(或潜在对象)的集合,则对象在等价测试方面被可见修改

    如果对象O1 用作哈希表H 中的键,然后根据H 的等价测试进行可见修改,那么如果O1 或任何对象,后果是未指定的O2 等同于等价测试下的O1(修改前或修改后),用作对H 进一步操作的key。使用O1 作为键的后果是未指定的,即使O1 被明显修改,然后以撤消可见修改的方式再次修改。

    在您的示例中,hash table testeql,表示修改 密钥(向*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
    

    因此,您可以看到*ht-1* 被键入特定的对象,而不是任何看起来像它的东西。

    另一方面,考虑一个equal 哈希表:

    (defparameter *ht-2* (make-hash-table :test 'equal))
    (setf (gethash *key* *ht-2*) 20)
    *ht-2*
    ==> #S(HASH-TABLE :TEST FASTHASH-EQUAL ((42) . 20))
    (gethash *key* *ht-2*)
    ==> 20; T
    (setf (car *key*) 7)            ; **visible modification**!
    (gethash '(7) *ht-2*)
    ==> unspecified!
    (gethash *key* *ht-2*)
    ==> unspecified!
    (setf (car *key*) 42)           ; restore key
    (gethash '(42) *ht-2*)
    ==> unspecified!
    (gethash *key* *ht-2*)
    ==> unspecified!
    

    底线是:不要明显修改哈希表键!

    【讨论】:

    • 所以根据规范,恢复 (car key) 到 42 仍然是未定义的行为,它恰好在这里工作,对吧?另外,为什么'eql/'equal 会变成'fasthash-eql/'fasthash-equal?这是否意味着在哈希表中只能使用预先确定的测试函数?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-31
    • 1970-01-01
    • 1970-01-01
    • 2011-08-19
    • 1970-01-01
    相关资源
    最近更新 更多