Emacs Lisp:#s 不会每次都创建新的散列 table

Emacs Lisp: #s does not create a new hash table each time

我有以下功能:

(defun inc-map ()
  (let ((ht #s(hash-table test contents-hash))) 
    (dolist (i (list 1 2 3 4))
      (let ((old-val (or (gethash "foo" ht)
             0)))
    (puthash "foo" (+ 1 old-val) ht)))
    ht))

尽管该函数似乎在本地定义了 ht 符号,但该函数似乎并不具有引用透明性。特别是,调用它一次 returns 哈希 table "foo" -> 4,第二次调用它 returns "foo" -> 8,第三次 return s "foo" -> 12 等等。

这里到底发生了什么,我如何将此函数更改为引用透明(并且每次 return "foo" -> 4)?

这可能被认为是一个(轻微的)文档错误,因为它有点过于坚定地暗示使用印刷表示会创建一个 new 散列 table --一个容易被误解的声明。

但是,您会注意到文档说是 elisp reader 识别散列 table 的打印表示。

因此使用 #s 与调用 make-hash-table 不同。这里的区别相当于引用一个列表'(1 2 3)和调用(list 1 2 3).

的区别

每种情况下的前者都由 reader 处理,因此可以看到相同的单个结果对象(分别为散列 table 或列表)在每次评估期间。

相反,在后一种情况下,reader 正在生成代码,在评估时,将创建一个新的散列 table 或列表;因此您在每次评估期间都会看到一个新对象。