假设在库中定义了一个样本函数(这个问题的前提条件是该库中的所有定义都不能被修改,类似于"只读"):
(defun sample ()
(foo)
(bar)
(baz))
Run Code Online (Sandbox Code Playgroud)
我想使用这个库,但功能sample无法满足我的要求,我想要的是:
(defun sample ()
(foo)
(when condition
(bar))
(baz))
Run Code Online (Sandbox Code Playgroud)
有人告诉我使用defadvice,但我注意到defadvice只能在调用之前或之后插入代码sample,例如:
(before-advice ...)
(sample)
(after-advice ...)
Run Code Online (Sandbox Code Playgroud)
它不能修改sample自己的定义.那么,我怎样才能慷慨地实现这一目标呢?我是否应该重写sample自己,称为my-sample或sample2?
sds的答案是有效的,除了你可能只想建议bar何时sample执行,所以你需要建议样本以激活和停用建议bar.我的with-temporary-advice宏有助于此:
(defmacro with-temporary-advice (function class name &rest body)
"Enable the specified advice, evaluate BODY, then disable the advice."
`(unwind-protect
(progn
(ad-enable-advice ,function ,class ,name)
(ad-activate ,function)
,@body)
(ad-disable-advice ,function ,class ,name)
(ad-activate ,function)))
(defadvice bar (around my-conditional-bar disable)
;; This advice disabled by default, and enabled dynamically.
(when condition
ad-do-it))
(defadvice sample (around my-sample-advice activate)
"Make execution of `bar' conditional when running `sample'."
(with-temporary-advice 'bar 'around 'my-conditional-bar
ad-do-it))
Run Code Online (Sandbox Code Playgroud)
请注意,如果bar在sample执行时也以其他方式调用,则建议也将适用于这些调用,因此如果可能,您应该考虑到这一点.
或者,您可能更愿意在需要时flet重新定义bar.当然,这与第一种解决方案有同样的警告.
(defadvice sample (around my-sample-advice activate)
"Make execution of `bar' conditional when running `sample'."
(if condition
ad-do-it
(flet ((bar () nil))
ad-do-it)))
Run Code Online (Sandbox Code Playgroud)
这更容易阅读,但由于我不明白的原因flet,从Emacs 24.3开始,不再支持.它的文档字符串建议使用cl-flet,但作为cl-flet使用词法绑定,它实际上不起作用.最好的我可以说,它听起来flet并没有真正消失,但目前的建议似乎是使用建议.
还要注意,如果在内部bar,不需要的行为取决于某个变量,那么最好使用let该变量上的flet绑定而不是对函数的绑定.
编辑:
当然,这些方法确实使得查看正在发生的事情变得更加困难.根据具体情况,最好简单地重新定义sample函数以执行您想要的操作(或编写my-sample函数以在其位置调用,如您所建议的那样).
| 归档时间: |
|
| 查看次数: |
610 次 |
| 最近记录: |