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

欢迎!请查阅关于页面以了解该功能的工作原理。

0
记录和类型
  1. 我的项目依赖于库"lib"。
  2. 这个库有一个包含10个功能的协议lib.core/P和实现该协议的记录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 中调用相同的功能。另一个方法是使用协议的低级别实现功能来外部提供操作的扩展。

协议的一个大好处是它们可以被外部扩展,在类型之外。协议实际上只是包含类型到函数实现的映射的映射。您可以定义一个refine宏,它展开以拉取基本实现,使用精炼修改,并将这些方法添加到协议映射中。这对我来说有点过于复杂,但它是可能的。

您还可以使用多方法以及关键字层次结构支持作为另一个选项(缺点是需要10个或更多多方法)。

+1

也许你可以这样使其变为 "Q 拥有 R"。在这种情况下,你的工作几乎已经完成了。

也许你需要分叉这个库来实现你所需要的功能(或更容易扩展)。

你可以在“数据类型”页面中找到关于 Clojure 排除实现继承的一些理由:https://clojure.org/reference/datatypes#_datatypes_and_protocols_are_opinionated

"Q 拥有 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)`
这正是预期的行为。

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

编辑
我使用“精炼”一词是因为“具体派生是错误的”注意事项。结果可能是复制实现而不是派生。
...