覆盖emacs lisp函数的首选方法?

iai*_*inH 19 emacs overriding

我已经重写和单机测试的内部功能通过与Emacs的24捆绑在一起的Emacs的功能之一调用的行为是什么合并的首选方式-例如在我的init.el-我的函数的行为覆盖捆绑功能?

我跟随了advicevs fset等的各种线程并且感到困惑.

eve*_*_jr 22

@iainH你倾向于通过描述你想要实现的目标,然后到目前为止你所拥有的目标来更快地得到一个有用的答案.我要求代码试图帮助你做你想做的事,而不必覆盖任何东西.

我仍然不明白为什么你不只是使用defun虽然?我怀疑你defun在init文件中使用了什么,但是原始函数还没有加载(参见autoload).一段时间后,您可以执行某些操作以使具有原始定义的文件加载,并且您的自定义函数将被原始文件覆盖.

如果这是问题,你有三个选项(假设你想要telnet-initial-filter从"telnet.el" 覆盖):

  1. 在定义自己的版本之前自己加载文件.

    (require 'telnet)
    (defun telnet-initial-filter (proc string)
      ...)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 只有在使用eval-after-load机制加载文件后,才能直接使用Emacs加载函数 .

    (eval-after-load "telnet"
      '(defun telnet-initial-filter (proc string)
         ...))
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用建议.

其中,2是最好的.1也没关系,但你必须加载一个你可能永远不会在会话中使用的文件.3是最糟糕的.任何涉及的内容defadvice 都应作为最后的选择.

  • 为什么“defadvice”如此糟糕? (2认同)
  • @katspaugh正如@phils还推断:`defadvice`更适合于修饰现有行为而不是完全替换它 - 就像在这种情况下一样.`defadvice`允许你添加行为_before_; _后_; 和_around_现有功能.`defadvice`确实允许你替换行为,但我认为上面的解决方案2在这里是最合适的. (2认同)
  • 使用“新”建议函数,您可以使用 `advice-add` 来覆盖一个函数:`(advice-add 'old-function :override #'my-new-function)`。您甚至可以在定义函数之前添加建议。 (2认同)

The*_*eJJ 6

有一种“新”建议方法,甚至可以在加载原始函数之前就设置函数替换。

(defun something-fixed ()
  ...
  )
(advice-add 'original-function :override #'something-fixed)
Run Code Online (Sandbox Code Playgroud)

这甚至可以与您的初始化文件结合使用eval-buffer


tri*_*eee 5

只是为了让这个问题保持独立,这里是如何通过建议来做到这一点.

(defadvice telnet-initial-filter (around my-telnet-initial-filter-stuff act)
  "Things to do when running `telnet-initial-filter'."
  (message "Before")
  ad-do-it
  (message "After") )
Run Code Online (Sandbox Code Playgroud)

如果您想要包装而不是替换现有函数(在这种情况下只重新定义它),这显然很有用.

有关使用建议的更多信息,请参阅手册.

  • 我有时会使用建议来完全重新定义函数.使用around建议而不是仅使用`defun`重新定义函数的优点是,建议还会覆盖函数的任何未来重定义(例如,直到重新定义函数的代码之后才加载包). (3认同)