带有所选项目的 Clojure 集合原子

Clojure collection atom with selected item

在 Clojure(实际上是 ClojureScript)中完成以下任务的最佳方法是什么:

到目前为止我想到的可能性:

  1. 使 xs 成为一个由 T 组成的向量的原子,并确保每个 T 元素都知道自己的索引。将 x 替换为 x_idx,后者存储 selected 项(或 nil)的索引。选择一个元素只是意味着获取它的索引并将 x_idx 更改为该索引,这两者都是恒定时间操作。这样做的缺点是它使结构有点不那么优雅和简单:我总是传递 selected 项目的 index,以及我想要的每个操作do 必须使用索引而不是项目本身,就像它希望的那样。由于我的 T 对象很小,所以如果有一个 T.
  2. 类型的“selected 对象”变量会更令人愉快
  3. 使xs成为原子向量,x成为存储T的原子。现在 xT,这很好,但是当我想更新关于 x 的信息时,我必须两次调用 reset!swap! : 一个用于 x ,一个用于 xsx 代表的元素。不雅的原因显而易见。而且我必须快速连续地执行这些操作,否则数据会出现不一致:在两次调用之间,监听 xs 的事件侦听器将看到处于一种状态的 selected 项目,听 x 的人会看到另一种状态。
  4. T 元素一个字段来判断它们是否 selected,然后去掉 x。如果可以一次 selected 多个项目,这将是正确的,但由于只能 selected,所以每次我想要 select 时,它只会让我进行线性搜索编辑项目,很烂。

这个问题的重点不是要解决某个特定问题(上述任何可能性都适用于我正在处理的小项目的范围),而是要了解 Clojure 数据结构。这似乎是一种足够普遍的情况,因此围绕它会有一些结构。欢迎回复“您应该尝试完全回答一个不同的问题...”。

你(我)想研究 cursors 和 reactions,这是试剂原子的两个更高级的特性。它们可用于在其中包含一个集合和一个自动更新的选定元素。例如,参见 here

假设您有一个 r/atom 保持对象的矢量,并且您想要一个可以更改并且可以直接编辑的选定对象。实现此目的的一种方法是保留一个原子来存储所选项目的索引,然后

(defn my-get-set
  ([_k] (@vector-of-items @idx-of-selected-item))
  ([_k v] (reagent.core/rswap! my-state-vector assoc @idx-of-selected-item v)))

(def selected-item (reagent.core/cursor my-get-set []))

编辑:reagent.core/cursor my-get-set nil 更改为 reagent.core/cursor my-get-set []。前者导致问题。