Joe*_*per 7 java state clojure hashmap
我对Clojure和函数式编程相当新,我一直在努力解决以下问题.我想为一系列令牌(字符串)分配一个唯一且稳定的索引.由于查找比插入更多,因此哈希映射似乎是要走的路.
在Java中,我会写一些东西
int last = 0;
HashMap<String, Integer> lut = new HashMap<String, Integer>();
function Integer getIndex(String token) {
Integer index = lut.get(token);
if(index == null)
last++;
lut.put(token, last);
return last;
else {
return index;
}
}
Run Code Online (Sandbox Code Playgroud)
Clojure中的音译版本就像
(def last-index (atom 0))
(def lookup-table (atom {}))
(defn get-index [token]
(if (nil? (get @lookup-table token))
(do
(swap! last-index inc)
(swap! lookup-table assoc token @last-index)
@last-index)
(get @lookup-table token)))
Run Code Online (Sandbox Code Playgroud)
但这似乎并不是非常自我,因为它基本上是副作用,甚至没有隐藏它.
那么如果没有两个原子来保持状态,你会怎么做呢?
Ankur 给出的答案不是线程安全的,尽管我不认为 seh 对原因的描述很有帮助,而且他的替代方案更糟糕。可以合理地说“好吧,我现在不担心多线程”,在这种情况下,答案就很好。但是,即使您在任何特定情况下都不需要这种保证,能够安全地编写此类内容也是很有价值的,唯一安全的方法是在 内部执行所有逻辑swap!,如下所示:
(let [m (atom {})]
(defn get-index [token]
(get (swap! m
#(assoc % token (or (% token) (count %))))
token)))
Run Code Online (Sandbox Code Playgroud)
swap!您可以通过避免调用函数时如果已经存在条目来加快速度,并且如果输入后已经存在条目则避免关联,swap!但您必须“仔细检查”映射在分配当前令牌之前没有条目(count %),因为在您开始swap!ing 之前(但在您决定swap!,并为当前令牌分配了一个值,在这种情况下您必须尊重该任务而不是制定新任务。
编辑:顺便说一句,Java 版本当然也有同样的线程安全问题,因为默认情况下 Java 中的所有内容都是可变的并且不是线程安全的。至少在 Clojure 中你必须放一个!在那里放一个 ,说“是的,我知道这很危险,我知道我在做什么。”
所以从某种意义上说,Ankur 的解决方案是Java 代码的完美翻译,但更好的是改进它!
| 归档时间: |
|
| 查看次数: |
443 次 |
| 最近记录: |