2

Erlang で実装された単純な車のプロセスがあります。

-module(cars).
-compile(export_all).

-record(state, {count=1}).

make_car() ->
  spawn_link(fun() -> car_proc(#state{}) end).

car_proc(S) ->
    receive
        {idle, X} ->
            io:format("idling for ~p second(s)~n", [X]),
            timer:sleep(X*1000);
        {move, {X,Y}} ->
            io:format("move; x=~p, y=~p~n", [X,Y]);
        {stop, Reason} ->
            X = S#state.count,
            io:format("stopped with count ~p because ~p~n", [X+1, Reason])
    end,
    X = S#state.count,
    car_proc(S#state{count=X+1}).

アイドル状態にすることはできますが、idle を 2 回続けて呼び出すと、次のように壊れます。

59> C = cars:make_car().
<0.207.0>
60> C!{idle,1}.         
idling for 1 second(s)
{idle,1}
61> C!{idle,1}.         
idling for 1 second(s)
{idle,1}
62> 
=ERROR REPORT==== 9-Apr-2013::00:00:00 ===
Error in process <0.207.0> with exit value: {{badmatch,2},[{cars,car_proc,1,[{file,"cars.erl"},{line,20}]}]}

** exception error: no match of right hand side value 2
     in function  cars:car_proc/1 (cars.erl, line 20)

なんで?

4

1 に答える 1

4

エラーは 20 行目で発生します。

X = S#state.count

パターンマッチングに失敗したために発生します。変数 'X' はこの行で既に定義されており、受信ブロックで決定されているため、その値は 1 です。

receive
        {idle, X} ->

Erlang では、変数の値は 1 回しか定義できません。メッセージ {idle, 1} を送信すると、最初に X が 1 になり、S#state.count のデフォルト値が 1 になります。その場合、'X' は S#state.count に一致します。{idle, 1} を 2 回送信すると、X は 1 で、S#state.count は 2 になります (つまり、X と S#state.count は等しくありません)。そのため、パターン マッチングでエラーが発生します。この問題を回避するには、別の変数を使用できます。最後の 2 行を変更する

X = S#state.count,
car_proc(S#state{count=X+1}).

Count = S#state.count,
car_proc(S#state{count=Count+1}).

そして、幸せになります!

于 2013-04-09T03:12:25.883 に答える