有一个返回字符序列的函数,我需要修改它以允许将元数据附加到某些字符(但不是全部)。 Clojure 不支持原始类型上的“with-meta”。因此,可能的选择是:
- 返回[字符,元数据]的向量序列;
优点:简单、数据和元数据捆绑在一起
缺点:需要从向量中提取数据
- 返回两个单独的序列,一个用于字符,一个用于元数据,调用者如果关心元数据,则大多数情况下会同时迭代这些序列;
优点:调用者不必从每个流元素中提取数据,如果他愿意,可以丢弃元序列
缺点:需要同时迭代两个序列,如果需要元数据,调用方会更加复杂
- 引入一些包含一个字符并允许将元附加到自身的记录包装器(Clojure 记录实现 IMeta);
优点:数据和元数据捆绑在一起
缺点:需要从记录中提取数据
- 你更好的选择。
哪种方法更好?
最佳答案
使用矢量/ map 序列,例如
({:char 'x' :meta <...>} {:char 'y' :meta <...>} {:char 'z' :meta <...>} ...)
; or
(['x' <...>] ['y' <...>] ['z' <...>] ...)
看起来对我来说是最好的选择,如果我有这样的任务,我会自己做。然后,例如,编写一个将此类序列转换回字符序列的函数非常简单:
(defn characters [s] (map :char s))
; or
(defn characters [s] (map first s))
同时遍历字符和元数据也很容易使用解构绑定(bind):
(doseq [{:keys [char meta]} s] ...)
; or
(doseq [[char meta] s] ...)
使用什么( map 或矢量)主要是个人喜好问题。
IMO,使用记录及其 IMeta
接口(interface)不太好:我认为这种元数据主要用于与语言相关的代码(宏、代码预处理、语法扩展等)和不适用于域代码。当然,我的这个假设可能是错误的。
使用两个并行序列是最糟糕的选择,因为它不像单个序列那样方便界面用户。使用我上面编写的函数丢弃元数据非常简单,如果所有序列都是惰性的,它甚至不会对性能产生影响。
关于Clojure:如何模拟向流中的字符添加元数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13860810/