2017-12-07 1 views
2

最近、私は多数のキー値を更新するという問題に取り組んだ。エリクシールに状態を保存する

当然のことながら、私は、Map.put/3ような操作で、Mapを用いて検討しました。

しかし、これはエリクサーでデータ構造の不変の性質を考えると、不十分なように見えた:

iex> m = Map.put(%{}, :a, 1) 
%{a: 1} 
iex> Map.put(m, :b, 2) 
%{a: 1, b: 2} 
iex> m 
%{a: 1} 

私はその後GenServerMapの状態を保持し、かつhandle_cast/3呼び出しを使用してそれを更新することで問題を解決しました。

は一般的に、これは正しいアプローチである、またはこれはあまりにもここでしたか?

答えて

6

私は、一般的に [...] GenServerMapの状態を保持することによって問題を解決し、これは正しいアプローチである、またはこれはあまりにもここでしたか?

それは頻繁にあなたの目標に依存します。 には多くの異なる方法があります。の状態です。以下のような再バインド変数:

m = Map.put(%{}, :a, 1) 
#⇒ %{a: 1} 
m = Map.put(m, :b, 2) 
#⇒ %{a: 1, b: 2} 

はない何も行います。ローカル変数mをRHOにバインドし、制御フローがスコープから離れるとすぐに、この変数はガベージコレクションされます。単一のスコープ内で前述のマップが必要かどうかにかかわらず、GenServer(および他の州の保有者)は過剰です。


OTOH、あなたが長い時間のために状態を保存し、異なるスコープ間でそれを共有する必要がある場合(例えば、異なるプロセス間で、)GenServerはそれを達成する最も簡単な方法です。エリクサーでは、我々は、単純なメモリー内のストレージとして使用されているGenServerのための定型を減少させるAgentモジュールを持っていますが、私のアドバイスは常にGenServerを使用することです:遅かれ早かれAgentあなたの目的のためにあまりにもタイトになります。

また、1はプロセス間で共有メモリ内のキーと値のストレージを、維持するためにetsモジュールを使用する場合があります。

detsは、の間に状態を保存する方法です。

そして、最後に、mnesiaが再起動し、異なるノード両者の状態を共有するOTPネイティブなアプローチである(分散環境で。)

2

あなたの最初のアプローチは正しかったです。あなたはちょっと間違っています。

あなたがマップを更新するときは、ここのように、変数を再バインドする必要があります

iex> m = Map.put(%{}, :a, 1) 
%{a: 1} 
iex> m = Map.put(m, :b, 2) 
%{a: 1, b: 2} 
iex> m 
%{a: 1, b: 2} 

をしかし、あなたはそれが変数を変異させていないことをここundestandなきゃ、それは新しいマップを作成し、同じにそれを再バインド変数。

さて、このアプローチは最も簡単なものであり、あなたがそれを使用するすべての関数にこのマップを渡す必要があるだろう。代わりに、Agentモジュールの使用を検討することもできます。それが何であり、何が使用されているかに関するすべての情報は、そのドキュメントにあります。

関連する問題