clojure银行账户汇款示例

时间:2017-03-02 20:39:03

标签: java clojure stm

我是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实例?

1 个答案:

答案 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被视为"低级"现在很少使用。参见: