假设在库中定义了一个示例函数(此问题的前提条件是此库中的所有定义都不能修改,类似于“只读”):
(defun sample ()
(foo)
(bar)
(baz))我想使用这个库,但是函数sample不能满足我的请求,我想要的是:
(defun sample ()
(foo)
(when condition
(bar))
(baz))有人告诉我使用defadvice,但我注意到defadvice只能在sample调用之前或之后插入代码,例如:
(before-advice ...)
(sample)
(after-advice ...)它不能修改sample本身的定义。那么,我如何才能优雅地实现这一点呢?我应该自己重写一个名为my-sample或sample2的sample吗
发布于 2013-04-10 12:26:41
sds的答案是有效的,除了您可能只想在sample执行时向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))请注意,如果在执行sample时还以其他方式调用bar,则建议也适用于这些调用,因此如果有可能,您应该考虑到这一点。
或者,在需要时,您可能更喜欢使用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)))这读起来简单多了,但由于我不明白的原因,从Emacs24.3开始,flet不再受欢迎。它的文档字符串建议使用cl-flet,但由于cl-flet使用词法绑定,这实际上并不起作用。据我所知,听起来flet实际上并没有消失,但目前的建议似乎是使用建议。
还要注意,如果在bar中,不想要的行为依赖于某个变量,那么更可取的做法是对该变量使用let绑定,而不是对函数使用flet绑定。
编辑:
当然,这些方法确实让我们更难看到正在发生的事情。根据具体情况,最好是简单地重新定义sample函数来执行您想要的操作(或者按照您的建议编写一个my-sample函数来代替它进行调用)。
发布于 2013-04-10 21:53:41
其他人已经提供了很好的答案,但由于一些人抱怨flet的耻辱,我将展示我将使用的:
(defvar my-inhibit-bar nil)
(defadvice bar (around my-condition activate)
(unless my-inhibit-bar ad-do-it))
(defadvice sample (around my-condition activate)
(let ((my-inhibit-bar (not condition)))
ad-do-it))快看,妈妈!没有flet和丑陋的激活/停用!当你使用C-h f bar的时候,它会清楚地告诉你,这比你看到的要多得多。另外,我实际上会使用新的advice-add:
(defvar my-inhibit-bar nil)
(defun my-bar-advice (doit &rest args)
(unless my-inhibit-bar (apply doit args)))
(advice-add :around 'bar #'my-bar-advice)
(defun my-sample-advice (doit &rest args)
(let ((my-inhibit-bar (not condition)))
(apply doit args)))
(advice-add :around 'sample #'my-sample-advice)发布于 2013-04-10 12:07:18
您应该使用around建议来建议function bar:
(defadvice bar (around my-condition)
(when condition
ad-do-it))https://stackoverflow.com/questions/15916124
复制相似问题