请在2024 年 Clojure 状态调查中分享您的想法!

欢迎!请参阅关于页以查看更多关于此功能的信息。

0
记录和类型
  1. 我的项目依赖于库 "lib"。
  2. 此库有一个协议 lib.core/P ,包含 10 个函数和一个实现该协议的记录 lib.core/R
  3. 在我的项目中,我需要一个类似 R 的记录 my.core/Q:在这 10 个函数中,只有 1 个不同。

实现 Q 的选项有哪些?
a) 从 R 中复制粘贴 其他 9 个函数。
b) 还有什么其他方法?

一种“记录精炼”类型的功能是否值得?

(defrecord Q [a b c]
  :refines lib.core/R
  lib.core/P
  (just-my-one-changed-fn [] ...))

2 个答案

+1

被选中
 
最佳答案

我认为,“精炼”不太可能被视为一项增强功能,因为这涉及到对具体派生的哲学反对。

处理此问题的一种方法是让 R 和 Q 中的 impls 调用相同的函数。另一种方法是使用协议的低级实现功能来外部提供扩展。

协议的一大好处是它们可以外部扩展,超出类型。协议实际上是包含类型到函数 impls 映射的映射。您可以使用一个 refine 宏将其展开以提取基本 impls、修改它们并将这些方法添加到协议映射中。这对我来说有些复杂,但这是可能的。

您还可以使用多态方法和关键字层次支持作为另一种选择(缺点是需要10个多态方法或类似数量的方法)。

+1

也许您可以将其修改为“Q拥有R”。在这种情况下,您的任务就几乎完成了。

也许您需要分叉库来实现您所需的功能(或更容易进行扩展)。

您可以在“数据类型”页面找到Clojure排除实现继承的理由:[链接](https://clojure.org/reference/datatypes#_datatypes_and_protocols_are_opinionated)。

"Q has-an R" `(defrecord Q [r]` 组合确实可以避免复制粘贴,但是我仍然需要为Q中的其他9个函数定义以及代理r字段调用;并且从行为上来说,并不总是可行,例如
- 比如,`(f r)`调用`(my-one-fn r)`
- 然后,`(f q)`代理到`(f r)`
- 这是`(my-one-fn r)`而不是`(my-one-changed-fn q)`
这是预期的行为。

无论如何,这个提及受到了很好的接纳!

编辑了
我使用“refinement”这个词,因为“具体派生是糟糕的”那里。结果可能是拷贝覆盖实现,不一定是派生。
...