我是clojure
的新手,我正在尝试实现经典的并发示例aka bank account transfer
。我想使用transactional memory
实现它。
以下是java
static class Account {
private double balance;
public synchronized void withdraw(double value) {
balance -= value;
}
public synchronized void deposit(double value) {
balance += value;
}
}
static synchronized void transfer(Account from, Account to, double amount) {
from.withdraw(amount);
to.deposit(amount);
}
在我的实施中不确定,但似乎有效。
这是clojure
(deftype Account [balance])
(def account1 (Account. (ref 100)))
(def account2 (Account. (ref 100)))
(defn print-accs []
(println " account 1 => " (deref (.balance account1))
" account 2 => " (deref (.balance account2))))
(defn transfer [from to amount]
(dosync
(alter (.balance from) - amount)
(alter (.balance to) + amount)))
(print-accs) ; 100 100
(transfer account1 account2 10)
(print-accs) ; 90 110
使用transactional memory
或正确实施bank account transfer
是一个正确的例子吗?我是否将ref
更正用于该字段,或者是否应将其用于整个Account
实例?
答案 0 :(得分:3)
您不需要deftype
,但看起来不错。我会简化一下:
(def account1 (ref 100))
(def account2 (ref 100))
(defn print-accs []
(println " account 1 => " @account1
" account 2 => " @account2 ))
(defn transfer [from to amount]
(dosync
(alter account1 - amount)
(alter account2 + amount)))
(print-accs) ; 100 100
(transfer account1 account2 10)
(print-accs) ; 90 110
我建议的一件事是review The Clojure Cheatsheet,并始终打开浏览器标签。这些链接可以提供有关ClojureDocs.org such as that for dosync
的更多详细信息。享受!
对于像帐户余额这样的单一值,将余额包装在Account
记录中并不重要。如果要创建一组具有相同字段的记录,您可能需要defrecord
:
(defrecord Account [name balance])
大多数应用都是使用像
这样的普通地图开始的(def joe-acct (ref {:name "Joe" :balance 100.00})
因为它很简单&灵活。稍后,如果您想为地图提供一个类型名称,该地图始终由名称&平衡,你可以切换到
(defrecord Account [name balance])
(def joe-acct (ref (Account. "Joe" 100.00)))
deftype
被视为"低级"现在很少使用。参见: