2016-07-20 3 views
2

私は現在、この本の中でを学んでいます。グレートグッドユアアーラングについてはとフレッドハーバートがあり、そのうちの1つはマクロに関するものです。私は、変数(主に定数値)用のマクロを使用して理解Erlangでマクロ関数を使うのはいつですか?

は、しかし、私は機能としてマクロのユースケースを理解していません。たとえば、Herbertは次のように書いています。

"関数"マクロの定義は似ています。

-define(sub(X, Y), X-Y). 

理由だけではなく、他の場所の関数としてこれを定義しない:ここから別の番号を減算するために使用される単純なマクロですか?なぜマクロを使うのですか?コンパイラのパフォーマンス上の利点はありますか?これは単なる「この関数はとてもシンプルなので、1行に定義しましょう」というものですか?

私はディベートや好みの引数を開始しようとしていないんだけど、いくつかの生産Erlangのコードを見た後、私は、マクロ機能の使用状況の多くを気づき始めました。

答えて

2

を、マクロが(より安全-define(sub(X, Y), (X-Y))ようになり-define(sub(X, Y), X-Y)、)関数ではないのいずれかの明白な利点は、それができるということですカスタム関数呼び出しが禁止されているのでガードとして使用されます。

多くの場合、関数をインライン関数として定義する方が安全です。一方

は、何がしたいことは、最終的な場所にいくつかのローカルコンテキストを維持することですテストやショートカットでアサーションなどの他の興味深い例があります。

たとえば、のは、私は目的は「与えられたパターンに一致して、指定された値を返す、またはMミリ秒後に失敗」でのテストのための一般的なコールを作りたいとしましょう。

あなたが持ち歩くことができるデータ構造ではないので、コードでこの一般的なことをすることはできません。しかし、マクロで:

-define(wait_for(PAT, Timeout), 
     receive 
      PAT -> VAL 
     after Timeout -> 
      error(timeout) 
     end). 

このマクロは、その後に使用することができます。これにより

my_test() -> 
    Pid = start_whatever(), 
    %% ... 
    ?wait_for({'EXIT', Pid, Reason}, 5000), 
    ?assertMatch(shutdown, Reason). 

、私は、ネストの束を必要とすることなく、いくつかのテストでは、テキストの形を単純化することができますよ、そして機能では不可能な方法で。

はEUNITで定義されたアサーション自体が機能マクロを使用していることに注意してください、と。これは、同様にあなたがパターンとバインディングを運ぶとことはできませんでした空想のフォームを行うことができます

-define(assertMatch(PAT, TERM), 
     %% funs to avoid leaking bindings into parent scope 
     (fun() -> 
      try 
       PAT = TERM, 
       true 
      catch _:_ -> 
       error({assertion_failed, ?LINE, ...}) 
      end 
     end)()). 

に似て何かをしてくださいさもないと。

この最後のケースでは、?LINEマクロを使用しています。これは、マクロのもう1つの利点です。コールサイトに関する情報や地域(モジュール名、行番号など)を保持しておくことです。これは、テストの失敗を報告しているときなど、そのようなメタデータが必要な場合に便利です。

1

古いコードを探しているなら、関数呼び出しは非常に高価であるという仮定の下に小さな関数をインライン化する方法として使用されるマクロがあるかもしれません。それが本当かどうかは分かりませんが、今日心配する必要はありません。

マクロは

-define(MAX_TIMEOUT, 30 * 1000). 

%% ... 
    gen_server:call(my_server, {do_stuff, Data}, ?MAX_TIMEOUT), 
%% ... 

のように、私はほとんどがこの仕事のための環境変数を渡すことを好むが、それは起動時にそれらを読んで、どこかにそれらを隠しておくとアクセサを書くためのより多くの仕事だ、定数を定義するのに使用することができます。

最後に、あなたはいくつかの簡単なメタプログラミングを行うことができます。この場合

-define(MAKE_REQUEST_FUN(Method), 
     Method(Request, HTTPOptions, Options) -> 
      httpc:request(Method, Request, HTTPOptions, Options)). 
?MAKE_REQUEST_FUN(get). 
?MAKE_REQUEST_FUN(put). 

%% Now we've defined a get/3 that can be called as 
%% get(Request, [], []). 
関連する問題