Clojure勉強日記(その19 アトムを使った非協調的、同期的な更新
こんにちは。では続きに入ります。
前回はrefを用いたSTMについて書いていましたが、Clojureには別の方式として「アトム」があります。
違いとしては・・下記です。
複数のrefの更新はトランザクションを使って協調させなければならなかった。
アトムは単一の値を、他の値とは関係なく更新するのに使える。
・・・とりあえず、実際のコードで確認してみましょうか。
user=> (doc atom) ------------------------- clojure.core/atom ([x] [x & options]) Creates and returns an Atom with an initial value of x and zero or more options (in any order):
初期化方法はrefと同じです。
user=> (def current-state (atom "INACTIVE")) #'user/current-state user=> @current-state "INACTIVE" ; refでなくてAtomとして取得できる user=> current-state #<Atom@6b5cbaf2: "INACTIVE"> user=> (deref current-state) "INACTIVE"
更新する際にはreset!を使用します。
ただ、refと違って複数の状態をまとめたトランザクションなどは実施できません。
user=> (reset! current-state "ACTIVE") "ACTIVE"
そのため、複数の値を協調させたい場合はatomにマップを設定する形になります。
user=> (def current-message (atom {:sender "Sender1" :message "Message1"})) #'user/current-message user=> (reset! current-message {:sender "Sender2" :message "Message2"}) {:sender "Sender2", :message "Message2"}
マップ化した後に一部の値だけを設定したい場合はswap!とassocを使い、
元のマップの中身を入れ替えたものをatomとして再設定すればOKです。
user=> (swap! current-message assoc :message "Message3") {:sender "Sender2", :message "Message3"}
・・・なんか、いまいち位置づけが中途半端で使いどころは微妙かもしれませんが。
後は次のエージェントが長いため、一度ここで切って次の記事へ。