2024 Clojure 状况调查中分享您的想法!

欢迎!请参阅关于页面以获取更多有关工作方式的详细信息。

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

实现 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 调用相同的函数。另一种方法是使用协议的低级实现功能来外部提供扩展。

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

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

+1
by

也许您可以让它实现为“Q具有R”。在这种情况下,您的工作差不多就完成了。

也许您会分叉库以使其满足您的需求(或更易于扩展)。

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

by
"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)`
这正是期望的行为。

无论如何,提及得到了良好的反响!
by
编辑 by
我使用了“refinement”这个词,因为“具体派生是坏的”注释。结果可以是复制实现而不是派生。
...