Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 仅当元素在集合中时才从集合中移除元素_Clojure - Fatal编程技术网

Clojure 仅当元素在集合中时才从集合中移除元素

Clojure 仅当元素在集合中时才从集合中移除元素,clojure,Clojure,玩家列表定义为一组: (def players (atom #{})) 删除播放器的函数应根据元素是否在集合中返回不同的HTTP代码: (defn remove-player [player-name] (if (contains? @players player-name) (do (swap! players disj player-name) (status (response "") 200)) (status (response "") 404))

玩家列表定义为一组:

(def players (atom #{}))
删除播放器的函数应根据元素是否在集合中返回不同的HTTP代码:

(defn remove-player [player-name]
  (if (contains? @players player-name)
    (do (swap! players disj player-name)
        (status (response "") 200))
    (status (response "") 404)))
此代码的问题在于,它可能会向并发请求返回多个
200
,即使只有一个请求实际删除了元素


我想我需要原子地执行
contains?
disj
。我需要执行显式锁定还是有更好的方法?

交换本身是原子操作,因此在交换的计算函数中,可以确保第一个参数(原子的当前值)是一致的。就我个人而言,我会为其创建一个助手函数,如下所示:

(defn remove-existent [value set-a]
  (let [existed (atom false)]
    (swap! set-a
           #(if (contains? % value)
              (do (reset! existed true)
                  (disj % value))
              (do (reset! existed false) 
                  %))
    @existed))
如您所见,lambda表达式包含存在性检查和删除

user> (def players (atom #{:user1 :user2}))
#'user/players

user> (remove-existent :user100 players)
false

user> (remove-existent :user1 players)
true

user> @players
#{:user2}
更新

受@clojuremostly优秀元数据方法的启发,您可以将其做得更好:

(defn remove-existent [value set-a]
  (-> (swap! set-a #(with-meta (disj % value)
                      {:existed (contains? % value)}))
      meta
      :existed))

您只需向交换功能添加更多逻辑即可:

(for [el-rem [:valid-el :not-there]]
  (let [a (atom #{:valid-el :another-one})
        disj-res
        (swap! a
               (fn [a]
                 (with-meta (disj a el-rem)
                            {:before-count (count a)})))]
    [disj-res
     "removed:"
     el-rem
     (not (== (:before-count (meta disj-res))
              (count disj-res)))]))

然后比较返回值
disj res
的计数和元数据中的计数。如果它不同,那么
disj
确实删除了一个元素。如果不存在,则元素不存在。

如果条件为“交换”,则可以移动它。
swap函数使
包含?
disj
调用原子。你的意思是我应该在交换之前保存当前计数,然后比较它们吗?它不是有同样的问题吗?差异可以是任何值(+100,-50,…)不,即使atom在您下面更改,
swapdisj
时,code>仍将是快照。因此,它是完全安全的,而且应该快2倍,因为您不必在它上面运行
contains?
。谢谢,我不知道如何返回新集合和标志,您使用atom很好地解决了这个问题。更新了我的代码,将atom重置为false,如果该值不存在。我们真的需要重置它吗<代码>存在
是本地的,不是吗?是的,我们必须这样做。因为交换!可以重新启动多次,具体取决于其他线程对
播放器的更改。因此,如果我们有player1,而另一个线程将其删除,则交换!将重新启动,并且需要刷新现有的
。我们将元数据附加到更新集并将其放入atom中,对吗?要读取现有的元数据,我们需要新的set对象,不是吗?