Emacs Elisp:使用put/get代替defvar有什么缺点吗?
我有一个移动到行尾的函数,但是 当已经在行的末尾时,返回到之前调用它的最后一个点 这需要将最后一个点的值存储在某个位置。 目前我正在将这一点存储在例如Emacs Elisp:使用put/get代替defvar有什么缺点吗?,emacs,elisp,Emacs,Elisp,我有一个移动到行尾的函数,但是 当已经在行的末尾时,返回到之前调用它的最后一个点 这需要将最后一个点的值存储在某个位置。 目前我正在将这一点存储在例如(defvar last point 1)中,但我认为 封装会更好(好吧,一致性可能会更好,因为它仍然 外部可见)使用(将“我的移动结束行”放在最后一点1) 和(获取“我的移动行尾”最后一点) 这样做有什么缺点?属性比普通变量慢。此外,它们也较少使用和使用 因此,可能阅读您的代码的人不太理解您的代码 如果您想明确您的变量是一个内部变量,那么 用双破
(defvar last point 1)
中,但我认为
封装会更好(好吧,一致性可能会更好,因为它仍然
外部可见)使用(将“我的移动结束行”放在最后一点1)
和(获取“我的移动行尾”最后一点)
这样做有什么缺点?属性比普通变量慢。此外,它们也较少使用和使用 因此,可能阅读您的代码的人不太理解您的代码 如果您想明确您的变量是一个内部变量,那么 用双破折号来命名是一种惯例 `最后一点 还可以尝试在函数和变量的名称上添加前缀 不与Emacs中使用的名称冲突 最后,使用属性的主要问题是它们不是 buffer local,但您的变量应该在示例中:
(defvar my--last-point ())
(make-variable-buffer-local 'my--last-point)
(defun my-last-point ()
(interactive)
(if (and my--last-point (eolp))
(go to my--last-point and set it to nil))
(go to the end of line and set my--last-point))
这样,您的函数将不会使用中一个缓冲区的点值
另一个。用作变量的符号在其变量槽中只取一个值,但启用了一个属性列表,您可以在其中存储多个值
属性列表可用于将多个质量链接到单个符号上。对于此任务,变量更清晰。当您存储特定于该符号的信息时(如使用“disable”属性禁用命令),应该使用symbol属性,但这里的情况并非如此。我不太确定您的断言是否会导致该属性变慢
get
将在symbol plist上使用一个循环,在我的例子中,这个循环只有10个元素长,而symbol value
将执行一系列重定向检查。如果新属性被推到plist的头部而不是尾部,get
可能比symbol value
更快。在我的例子中,put
/get
的主要优点是函数变成了一个原子:它不关心任何外部变量。我可以移动它/重命名它/随便什么。我不必考虑这个函数所依赖的一个额外变量。@abo abo变量查找不涉及调用符号值
,就像属性访问不涉及调用符号plist
。相反,这两种操作都是基本操作,都有自己的操作码(varref
和get
)。因此,它们的性能可能是相同的,尽管属性列表查找通常具有复杂性O(n)
,而变量查找是固定时间的。@abo abo abo我不确定您是否可以在任何地方阅读此内容。我认为字节编译器的内部没有文档记录。但是,您可以阅读字节编译器源代码(在bytecomp.el
和friends中),也可以反汇编表单。例如,尝试(反汇编(byte compile sexp(lambda()user full name)))
或(反汇编(byte compile sexp(lambda()(get user full name'standard value)))
谢谢,我会看看您提到的内容。但是,字节码必须映射到C源代码,对吗?我看到get
有效地使用了symbol-plist
@abo-abo,但它是C语言中的函数调用,比Emacs-Lisp中的函数调用快得多。这是相对缓慢的。因此,(get'user full name'标准值)
比(plist get(symbol plist'user full name)标准值)
快得多,即使这两种形式在语义上是等效的。前者是一个单基元C操作,而后者在Emacs Lisp中涉及两个昂贵的函数调用。但是此信息是特定于此符号的,因为没有其他函数使用它。@abo abo不,它不是。它不是特定符号的特定和固有属性,而是恰好由符号的函数定义使用的数据。因此,符号属性在语义上是错误的位置。符号属性不是动态数据存储。那就是,嗯……变量:)我的C++-ish/JavaScript-ish直觉告诉我,这个的语义没有问题。正如我从Emacs C代码中看到的,实现这个过程不是太慢。“abo abo ER,嗯,C++和javascript不是精确的Emacs LISP,所以你的直觉可能不是这里最好的向导。使用一个变量,真的。符号属性不是数据存储。它们不像C++中的对象属性,而是更像修饰语(例如,代码>公共< /代码>,<代码>私有< /代码>,<代码> const 等)。您知道,符号属性是全局的,不是吗?是否确实要全局存储上一个点?对我来说,一个缓冲区局部变量似乎更合适。是的,我在问题中提到过它,它对这种情况并不重要。我正在寻找除此之外的其他缺点。在emacs帮助列表上问这个问题。那里有真正的emacs大师,看看他们对这个问题的看法会很有趣:abo abo:我认为你应该使用一个不同的例子?任何存储点都需要缓冲区本地,在这种情况下,put
/get
显然是不合适的。我知道你已经对此发表了评论,但这仍然是人们在阅读你的问题时首先会注意到的事情。