我理解协议如何用于向现有类引入新行为,但是它们(或任何其他Clojure机制)是否可以将状态引入现有类?更具体地说,我希望能够将地图与来自第三方库的类的实例相关联。
答案 0 :(得分:3)
协议在概念上与Java接口类似,因为它们根本不涉及状态或表示,所以我很确定你不能这样做,除非你将状态存储在对象本身之外。但是,你可以使用各种其他方法在Clojure中扩展(子类化)类来实现这一点,例如:使用proxy
或gen-class
。 (看到
http://clojure.org/java_interop#Java%20Interop-Implementing%20Interfaces%20and%20Extending%20Classes)
答案 1 :(得分:2)
您可以使用set-state
和get-state
功能创建协议。然后将它们扩展到您想要的类,并使用围绕某种类型的hashmap构建的实现。您不能将状态存储在外部对象中,但您可以让您的函数共享由对象键入的哈希表的引用。我认为这个解决方案可能有很多问题,比如你如何检测对象何时被GCed以及它的状态需要被清除?你可以使用WeakReference或其他东西,但这不是一件容易的事。
答案 2 :(得分:2)
首先,协议是接口定义,通常,您不希望在接口中指定状态。您通常希望将状态放在接口的实现中,请参阅下文。
对于大多数允许您实现接口或扩展类的clojure构造,最安全的方法 - 特别是如果您不拥有该类 - 是使用闭包来捕获状态。您可以捕获可变类型以实现可变状态(尽管如果可以的话,可能你想要避免的东西)。
来自http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/reify
的不可变示例 (str (let [f "foo"]
(reify Object
(toString [this] f))))
注意,如果你想要可变状态,这里的f可以是ref或var或atom,而不是字符串。
编辑:正如评论中所注意到的,我可能没有完全明确这一点:您可以使用defprotocol定义基于函数的接口,然后使用reify创建该协议的实例以捕获状态。编辑2:很抱歉让这个令人困惑。此代码实际上不适用于现有类,因为reify不支持它。代理可能作为一种替代方案,尽管文档没有将协议映射中的函数名称的状态简化为接口方法。
答案 3 :(得分:0)
您可以存储状态。你只需要在你的get和set方法中使用atom或ref以及引用和取消引用atom或ref