タプルを介して関数を呼び出す

少し前に、私はアーランで興味深い機会に出会いました。 モジュールの名前の代わりに、関数を呼び出すときに、最初の要素がモジュールの名前であるタプルを渡すと、関数が呼び出されます

アリティはもう1つ呼び出され、最後の引数は同じタプルになります。



例:

-module(my_module). -export([test/2]). test(Arg1,{?MODULE,Arg2}) -> io:format("Arg1:~p~nArg2:~p~n",[Arg1,Arg2]).
      
      





次のように呼び出すことができます。

 my_module:test(1,{my_module,2}).
      
      



かそこら
 {my_module,2}:test(1).
      
      







これはどのように適用できますか?


たとえば、すべてのデータがタプル(さらに便利なことにレコード -e)に格納される抽象データ型(データモデル)を作成する場合。

 -module(user). -export([new/0,save/1]). -export([name/1,set_name/1]). -export([proplist/1]). % record name must be same as module name. -record(user,{id,name}). new() -> {ok,#user{}}. name(#user{name=Name}) -> Name. set_name(NewName) -> {ok,State#user{name=NewName}}. % … Some other code ... save(#user{id=undefined,name=Name} = State) -> % Create new object in db; % ... {ok,State}; save(#user{id=ID,name=Name} = State) -> % Update an object in database % ... {ok,State}; proplist(#user{id=ID,name=Name}) -> [{id,ID}, {name,Name}].
      
      





結果は、コードで使用するのに非常に便利なユーザータイプです。

 {ok,User} = user:new(), {ok,User2} = User:set_name("SomeName"), {ok,User3} = User2:save(), UserName = User3:name().
      
      





原則として、アイデアは明確ですが、このスタイルでのプログラミングはアーランの方法ではなく、さらに、 Dialyzerコードの静的検証は複雑です。 さらに、このコードはこれとは異なります

 {ok,User} = user:new(), {ok,User2} = user:set_name("SomeName",User), {ok,User3} = user:save(User2), UserName = user:name(User3).
      
      





文字数のみ。 したがって、どこでも使用することはお勧めしません



私のプロジェクトでこの機能を使用したのは、抽象データ型に関数を作成し、それにアクセスするためのインターフェイスを知っている可能性があるためです(たとえば、前のモデルでは、 proplist()関数はインターフェイスとして機能します)。



RESTfulサービスを開発するときは、モデルごとにリソースを記述するのが非常に便利です。また、戻るときに、特定のモデルがどのモジュールに属しているかを知らずにリソースを必要なタイプに変換します。

 to_json(Resource) -> Proplist = Resource:proplist(), Json = mochijson2_fork:encode({struct,[Proplist]}), {ok,Json}. to_xml(Resource) -> Proplist = Resource:proplist(), XML = SomeProplistToXmlGenerator(Proplist), {ok,XML}.
      
      






All Articles