如何在Emacs Lisp中获取唯一对象ID?

时间:2012-08-25 14:37:11

标签: emacs elisp

emacs lisp是否具有提供唯一对象标识符的功能,例如,内存地址? Python有id(),它返回一个保证在当前现有对象中是唯一的整数。那么elisp呢?

3 个答案:

答案 0 :(得分:6)

我知道想要像id()这样的函数的唯一原因是比较对象,并确保它们仅在相同时进行比较(如同在相同的内存位置)。在Lisps中,这与Python中的做法略有不同:

在大多数lisps中,包括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”,它位于两者之间。

(编辑:我原来的答案可能不太清楚为什么eqequal之间的区别可能解决了原始海报所带来的问题)

答案 1 :(得分:4)

据我所知,Emacs Lisp中没有这样的功能。如果您只需要相等,请使用eq,它在幕后执行指针比较。 如果您需要可打印的唯一标识符,请使用cl包中的gensym。 如果您需要唯一标识符作为数据结构中的索引,请使用gensym(或维护您自己的唯一ID - gensym更简单,更不容易出错。)

有些语言会在每个对象中加入一个唯一的id,但这有一个代价:要么每个对象都需要额外的内存来存储id,要么id是从对象的地址派生的,这就排除了修改地址的作用。 Python选择支付费用,Emacs选择不支付。

答案 2 :(得分:4)

我提出问题的全部意义在于我正在寻找一种方法来区分具有相同名称的不同符号的打印表示。感谢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"

请注意'上的'#:foo - #:表示法是符号文字。如果没有',则会评估未处理的符号:

(symbol-name '#:foo)
  ==> "foo"
(symbol-name #:foo)
 ==> (void-variable #:foo)