如何将协议方法转发到现有类型?
问题描述:
如何定义从现有类型“继承”协议的新记录?如何将协议方法转发到现有类型?
为了清楚这个问题,我将以扩展Ubergraph为例进行说明,但Ubergraph只是一个例子;我正在寻找通用解决方案,而不仅仅是一个适用于Ubergraph的解决方案。假设我想为Ubergraph添加一个全局属性graph-name
。理想情况下,我可以做这样的事情:
(defrecord named-ubergraph [g graph-name])
(extend-type named-ubergraph
(all-the-protocols-supported-by ubergraph.core.Ubergraph)
(call-the-same-functions-replacing-first-argument-with '(this g))
当然,我可以看看Ubergraph源代码和手动编写所有的转发功能,但as you can see here,Ubergraph满足许多协议和许多协议的方法。
写了这么多的样板代码听起来不太合适,而且当我想要做的只是为ebergraph添加一个eensy-weensy位数据时,它看起来像很多工作。什么是更好的方法?
如果你认为我看错了,请随时重新考虑这个问题。
答
extend-type
将现有类型扩展到给定协议。 如果我正确理解你,你想扩展现有的记录来实现某种继承。 AFAIK,有没有简单的方法来做到这一点。 然而,如果你想要的是添加一个字段,你可以很容易地assoc
附加字段到现有的记录实例:
(defprotocol Cost
(cost [this price-list]))
(defrecord Car [name speed]
Cost
(cost [this price-list] (price-list (:name this))))
(def my-car (->Car "bmw" 200))
(def price-list {"bmw" 100000})
(cost my-car price-list)
;;=> 100000
(-> my-car
(assoc :color "blue")
(cost price-list))
;;=> 100000
更新: 我还发现Clojure的邮件列表上的这个梦幻般的讨论:defrecord与“继承”:https://groups.google.com/forum/#!topic/clojure/mr-o9sRyiZ0
只要与记录相关联是一个很好的见解!我知道Clojure允许这样做,但我没有想到这个问题。这立即解决了我目前的许多问题 - 使用理想的代码量:无!但是,我只是试着联合一个Ubergraph,这是行不通的。所以,我现在要解决这个问题了。 (向Ubergraph添加任意数据_is_实际上是我现在需要的主要实际原因。) –
嗯,Ubergraph甚至有[case statements](https://github.com/Engelberg/ubergraph/blob/320e284a6de6adb241df5dfeb9fd6383caea659c/src/ ubergraph/core.clj#L214),它可以防止“关联”到任意键。 –