emacs lisp 是否具有提供唯一对象标识符(例如内存地址)的功能?Python has id()
,它返回一个整数,保证在当前存在的对象中是唯一的。省略号呢?
3 回答
我知道想要一个函数的唯一原因id()
是比较对象,并确保它们只有在它们相同时才比较相等(如在相同的内存位置)。在 Lisps 中,这与 Python 中的做法有些不同:
在大多数 lisp 中,包括 elisp,有几种不同的相等概念。最昂贵和最弱的等价物是equal
. 这不是您想要的,因为如果两个列表(例如)具有相同的元素(使用 递归测试),则它们是相等的equal
。像这样
(equal (list 1 2) (list 1 2)) => T
是真的。在频谱的另一端是eq
,它测试“身份”而不是平等:
(eq (list 1 2) (list 1 2)) => NIL
这就是你想要的,我想。
因此,Python 似乎通过提供一个相等性测试来工作,然后提供一个函数,为每个对象提供一个内存位置,然后可以将其作为整数进行比较。另一方面,在 Elisp(至少也包括 Common Lisp)中,“平等”的含义不止一个。
请注意,还有“eql”,位于两者之间。
(编辑:我的原始答案可能不够清楚,为什么区分eq
并equal
可能解决了原始海报所遇到的问题)
据我所知,Emacs Lisp 中没有这样的功能。如果您只需要相等,请使用eq
,它在后台执行指针比较。如果您需要可打印的唯一标识符,请gensym
从cl
包中使用。如果您需要一个唯一标识符作为数据结构中的索引,请使用gensym
(或维护您自己的唯一 ID —gensym
更简单且不易出错)。
一些语言将唯一的 id 烘焙到每个对象中,但这需要付出代价:每个对象都需要额外的内存来存储 id,或者 id 是从对象的地址派生的,这样就无法修改地址。Python 选择付出代价,Emacs 选择不付出。
我提出这个问题的全部意义在于,我正在寻找一种方法来区分具有相同名称的不同符号的印刷表示。多亏了 elisp 手册,我发现了变量print-gensym
,当非 时nil
,它会导致#:
被添加到打印的未执行符号之前。此外,如果同一个调用print
多次打印相同的非实习符号,它将#N=
用`#N#标记第一个符号和后续符号。这正是我正在寻找的那种功能。例如:
(setq print-gensym t)
==> t
(make-symbol "foo")
==> #:foo
(setq a (make-symbol "foo"))
==> #:foo
(cons a a)
==> (#1=#:foo . #1#)
(setq b (make-symbol "foo"))
==> #:foo
(cons a b)
==> (#:foo . #:foo)
该#:
符号也适用于read
:
(setq a '#:foo)
==> #:foo
(symbol-name a)
==> "foo"
请注意'
on '#:foo
--#:
表示法是符号文字。如果没有'
,则评估 uninterned 符号:
(symbol-name '#:foo)
==> "foo"
(symbol-name #:foo)
==> (void-variable #:foo)