(defonce channels (atom []))
(defn register-channel! [id tag channel]
(swap! channels conj [id tag channel]))
(register-channel! "456" :player {})
@channels ;; => [["456" :player {}]]
id和tag是数据的索引,id是唯一的,tag不是。
我可以将conj
个新项目发送到频道。但是,使用现有ID调用register-channel!
不会conj
新项目,而是应更改现有项目的第三个元素channel。
这就是我所拥有的,有效的方法:
(defn register-channel! [id tag channel]
(let [without-id (remove #(= id (first %)) @channels)
with-id (conj without-id [id tag channel])]
(reset! channels with-id)))
我非常确定有更优雅的方式:)
请注意,我正在使用向量集合,因为我只有3个元素,如果没有明显的性能损失,我可以使用映射。但是,我需要编写函数来通过id或通过标记的通道来查找通道,例如
(defn one-by-id [id] (first (filter #(= id (first %)) @channels)))
(defn many-by-tag [tag] (filter #(= tag (second %)) @channels))
答案 0 :(得分:2)
如果你真的需要频道作为成对矢量,你可以像这样添加或替换新频道:
> (vec (assoc (into {} [[:a 1]]) :a 2))
[[:a 2]]
> (vec (assoc (into {} [[:a 1]]) :b 2))
[[:a 1] [:b 2]]
但这引出了一个问题,即你是否宁愿让频道本身成为地图。
将原子定义为空地图并完成工作!
(defonce channels (atom {}))
(defn register-channel! [id channel]
(swap! channels conj [id channel]))
> (register-channel! "456" {:a 1})
{"456" {:a 1}}
> (register-channel! "457" {:a 1})
{"456" {:a 1}, "457" {:a 1}}
> (register-channel! "457" {:a 2})
{"456" {:a 1}, "457" {:a 2}}