【问题标题】:How to acquire unique object id in Emacs Lisp?如何在 Emacs Lisp 中获取唯一的对象 ID?
【发布时间】:2012-08-27 09:44:25
【问题描述】:

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

【问题讨论】:

  • @NicolasDudebout:我猜它是用来索引哈希表、平衡树……
  • 在带有垃圾收集的语言中定义一个通用唯一的对象标识符是相当困难的。特别是,一个对象的内存地址并不像它看起来的唯一标识符那么好。实际上,id([1, 2]) == id([3, 4]) 在 CPython REPL 中的计算结果为 True,因为 [1, 2] 已被垃圾回收,而 [3, 4] 恰好分配在与 [1, 2] 相同的地址。
  • 其实不是为了索引,而是为了打印。例如,打印两个同名的不同符号会产生相同的结果,但是如果我们可以打印一个数字对象标识符,我们就可以从输出中判断出在程序中不同点引用的两个符号是否在事实相同的对象。
  • 小心:在大多数lisp(包括Elisp)中,同名符号是eq。如果您的意思是要打印 (list 1)(list 1) 彼此不同,我不确定在 Emacs 中是否可行。我也很难理解你为什么会关心。
  • 我认为这不对。 (eq 'symbol-1 (make-symbol "symbol-1")) 产生 nil。当然,在处理非内部符号时,查看对象的数字标识符可能会有所帮助。

标签: emacs elisp


【解决方案1】:

我知道想要像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”,介于两者之间。

(编辑:我最初的回答可能不够清楚,为什么 eqequal 之间的区别可能解决了原始发帖人遇到的问题)

【讨论】:

  • 请否决这个答案的人能解释一下它有什么问题吗?我可以看到寻找id() 等价物的唯一可能原因是比较对象。我的回答解释了在 Emacs lisp 中做到这一点的方法。
  • 我刚刚编辑了答案:希望它能更清楚地说明为什么它解决了 OP 的问题。
  • 我已经知道 elisp 的 eq 和 Python 的 is。 Python 的 is 的特殊之处在于它允许您打印具有相同 repr 的对象的两种不同数字表示。
【解决方案2】:

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

有些语言将唯一的 id 嵌入到每个对象中,但这有代价:每个对象都需要额外的内存来存储 id,或者 id 是从对象的地址派生的,这样就无法修改地址。 Python 选择付出代价,Emacs 选择不付出。

【讨论】:

    【解决方案3】:

    我提出这个问题的全部意义在于,我正在寻找一种方法来区分具有相同名称的不同符号的印刷表示。多亏了 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 上的'——#: 表示法是符号文字。如果没有 ',则会评估 uninterned 符号:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多