我正在开发一个小型社交媒体API,允许用户插入新的个人资料,将两个个人资料(例如朋友)连接在一起,然后根据“我的朋友的朋友”规则接收推荐。
现在,我正在尝试为Profile创建API。
我有一个原子,其中包含一个地图列表,每个配置文件一个。
(def profiles (atom ()))
(defn create [request]
(swap! profiles conj {:id (get-in request [:body "id"])
:name (get-in request [:body "name"])
:age (get-in request [:body "age"])
:recommendable (get-in request [:body "recommendable"])
:friends (list)
})
(created "")
)
当我遇到问题时,我正在尝试为API的GET http动词开发find-by-id。如何从上述列表中的映射中获取值,以便对其应用功能?
例如,在这里我试图使用过滤器功能仅向我返回包含给定ID的地图。但我不断收到错误消息:
(defn find-by-id [id]
(filter #(= (:id %) id) profiles)
)
Dont know how to create ISeq from: clojure.lang.Atom
在我看来,过滤器不适用于Atom。
发生同样的事情:
(defn delete-by-id [id]
(swap! profiles (remove #(= (:id %) id) profiles))
)
当我尝试使用@profiles时,结果是一个空数组。更糟糕的是,当我尝试使用REPL过滤器功能时,它工作得很好。
这让我想知道我在这里想念什么。
任何人都可以告诉我发生了什么事吗?
谢谢。
答案 0 :(得分:0)
第一个失败的原因是,正如它所说的,原子不是filter
所期望的序列。
filter
之前,您需要先从原子中除去序列:
; I'm dereferencing the atom using @ to get the list of profiles that it holds
(defn find-by-id [id]
(filter #(= (:id %) id) @profiles))
不过请注意,这不是最佳选择。您所依赖的状态profiles
可能在看似随机的时间发生变化(如果您有异步进程swap!
对它进行操作)。这可能会使调试复杂化,因为在将数据传递给filter
之前无法很好地处理数据。对于函数来说,依靠profiles
作为原子也是不好的,因为这与它的功能无关,您以后可以更改设计。使该函数完全依赖其参数并且不了解原子将是将来的证明。
(defn find-by-id [id profiles]
(filter #(= (:id %) id) profiles))
; Then call it like this. I renamed your atom here
(find-by-id some-id @profile-atom)
您的第二个示例失败,因为swap!
接受一个函数作为其第二个参数。我认为您打算使用reset!
,它会更改原子的值,而不管其之前是什么:
(defn delete-by-id [id]
(reset! profiles (remove #(= (:id %) id) @profiles)))
尽管如此,这也不是最佳选择。如果要基于先前状态更新原子,请改用swap!
并提供更新功能:
(defn delete-by-id [id]
(swap! profile-atom (fn [profiles] (remove #(= (:id %) id)) profiles)))
或更简洁地说:
(defn delete-by-id [id]
(swap! profile-atom (partial remove #(= (:id %) id))))
我正在部分应用remove
来实现功能。原子的旧状态作为最后一个参数传递给remove
。