Java clojure银行账户转账示例

Java clojure银行账户转账示例,java,clojure,stm,Java,Clojure,Stm,我不熟悉clojure,我正在尝试实现经典的并发示例aka银行账户转账。我想使用事务内存实现它 下面是java static class Account { private double balance; public synchronized void withdraw(double value) { balance -= value; } public synchronized void deposit(double value) {

我不熟悉
clojure
,我正在尝试实现经典的并发示例aka
银行账户转账
。我想使用
事务内存实现它

下面是
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

使用
事务性内存
或正确执行
银行账户转账
是否是一个恰当的例子?我是否对字段使用了
ref
正确,还是应该对整个
帐户
实例使用它?

您不需要
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
我推荐的一件事是始终打开浏览器选项卡。这些链接可以在ClojureDocs.org上找到更详细的信息。享受吧

更新 对于帐户余额这样的单个值,将余额包装到
帐户
记录中没有多大意义。如果要创建一组具有相同字段的记录,可能需要
defrecord

(defrecord Account [name balance])
大多数应用程序一开始都使用普通的地图,比如

(def joe-acct (ref {:name "Joe" :balance 100.00})
因为它简单灵活。稍后,如果要为始终由名称和余额组成的映射指定typename,可以切换到

(defrecord Account [name balance])
(def joe-acct (ref (Account. "Joe" 100.00))) 
deftype
被认为是“较低级别”,现在很少使用。见:


    • 您不需要
      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
      
      我推荐的一件事是始终打开浏览器选项卡。这些链接可以在ClojureDocs.org上找到更详细的信息。享受吧

      更新 对于帐户余额这样的单个值,将余额包装到
      帐户
      记录中没有多大意义。如果要创建一组具有相同字段的记录,可能需要
      defrecord

      (defrecord Account [name balance])
      
      大多数应用程序一开始都使用普通的地图,比如

      (def joe-acct (ref {:name "Joe" :balance 100.00})
      
      因为它简单灵活。稍后,如果要为始终由名称和余额组成的映射指定typename,可以切换到

      (defrecord Account [name balance])
      (def joe-acct (ref (Account. "Joe" 100.00))) 
      
      deftype
      被认为是“较低级别”,现在很少使用。见:


      我使用了
      deftype
      ,因为我想模拟为
      帐户创建一个特定的类。这就是为什么我问这样一个问题:我是否应该为
      帐户
      余额
      字段的
      Ref
      实例存储
      Ref
      ,因为我不确定。顺便问一下,您是否碰巧知道
      Ref
      何时从内存中删除?被GC引用?引用和其他任何对象一样是一个“对象”,当不再被引用时,它会被GC删除。对于Account实例,
      ref
      ?我为值设置了
      ref
      -如果我像这样将
      Account
      包装到
      ref
      (def-ref-acc(ref(Account.100)))
      ,会有区别吗?但是如果我有多个字段,我应该使用什么方法?整个类还是仅仅字段?好吧,我使用了
      deftype
      ,因为我想模拟为
      Account
      创建一个特定的类。这就是为什么我问这样一个问题:我是否应该为
      帐户
      余额
      字段的
      Ref
      实例存储
      Ref
      ,因为我不确定。顺便问一下,您是否碰巧知道
      Ref
      何时从内存中删除?被GC引用?引用和其他任何对象一样是一个“对象”,当不再被引用时,它会被GC删除。对于Account实例,
      ref
      ?我为值设置了
      ref
      -如果我像这样将
      Account
      包装到
      ref
      (def-ref-acc(ref(Account.100)))
      ,会有区别吗?但是如果我有多个字段,我应该使用什么方法?整个类还是仅字段?键入
      传输
      ?您将
      从传递到
      ,但稍后将使用
      帐户[12]
      哦。是否在
      传输中固定了typo
      ?您将
      从传递到
      ,但稍后将使用
      帐户[12]
      哦。固定的