我正在尝试使用另一个库中的实用程序函数在一个库中advise a number of methods,其中一些要建议的方法是使用(defn)
定义的,而另一些是使用(defprotocol)
定义的。
现在我正在使用this library,它使用(alter-var-root)
。我不关心我使用哪个库(或者我是否自己动手)。
我现在遇到的问题是,协议方法有时可以被建议,有时也不能,这取决于我不太清楚的因素。
如果我定义了一个协议,那么定义一个类型并实现该协议 in-line ,然后建议似乎永远不会起作用。我假设这是因为该类型直接扩展了JVM接口并跳过了变量。
如果在一个命名空间中,我定义了一个协议,然后建议它的方法,然后将协议扩展到一个类型,建议将不工作。
< / LI>如果在单个命名空间中,我定义了一个协议,然后将协议扩展到一个类型,然后建议协议的方法,建议将工作。
我想要做的是找到一种可靠的工作方法,并且不依赖于未定义的实现细节。 这可能吗?
答案 0 :(得分:2)
Clojure本身并不提供以可靠方式提供建议功能的任何可能性,即使是通过def
/ defn
定义的功能。请考虑以下示例:
(require '[richelieu.core :as advice])
(advice/defadvice add-one [f x] (inc (f x)))
(defn func-1 [x] x)
(def func-2 func-1)
(advice/advise-var #'func-1 add-one)
> (func-1 0)
1
> (func-2 0)
0
在评估表单(def func-2 func-1)
后,var func-2
将包含 var func-1
的绑定(换言之,其值),因此{{1}不会影响它。
尽管如此,像advice-var
这样的定义很少见,您可能已经注意到或使用了以下内容:
func-2
如果您建议(defn generic-function [generic-parameter x y z]
...)
(def specific-function-1 (partial generic-function <specific-arg-1>))
(def specific-function-2 (partial generic-function <specific-arg-2>))
...
,由于上述特性,任何特定功能都不会按预期工作。
如果建议对您来说至关重要,作为可能工作的解决方案,我假设如下:由于Clojure函数被编译为java类,您可以尝试{{3} } generic-function
和其他具有所需行为的方法(但是,当谈到替换协议/接口方法时,事情变得更加复杂:似乎你必须在实现特定协议/接口的每个类中替换所需的方法)。
否则,您需要为您想要建议的每个功能使用显式包装器。在这种情况下,宏可能有助于减少样板。