开发者

Records in a guard

I'm attempting to use a record in a guard as described here[1]. If I use the short 开发者_高级运维form described there:

handle(Msg, State) when Msg==#msg{to=void, no=3} ->

... I never get a match... however, if I fully expand it to:

handle(Msg, State) when Msg#msg.to==void, Msg#msg.no==3 ->

... all is well. As it seems I do with most erlang docs, am I reading it wrong?

Thanks, --tim

[1] - http://www1.erlang.org/doc/reference_manual/records.html#id2278275


When you say #msg{to=void, no=3} in a guard, all the fields that you haven't mentioned will be set to their default (usually undefined). So your guard is failing to match because some of the fields not listed don't match.

I tend to always use a pattern rather than a guard where possible, so I would write the clause as:

handle(Msg = #msg{to=void, no=3}, State) ->
    ...

This pattern requires Msg to msg record (a tuple the size of an msg record with the first element being msg), the to element must be void and the no element must be 3. The other elements of the msg record can be anything.


I see you solved the problem already. Just a note: in idiomatic Erlang you'd usually write the match like this:

handle(Msg = #msg{to = void, no = 3}, State) ->

Of course, it comes down to taste, and at times you'll want to use guards instead to get more pleasing line alignment.


You might want to use the following pattern instead, its succinct

handle(#msg{to=void, no=3}=Msg, State) ->
    do_stuff(Msg).

If you don't need the whole msg record value, but only some field within it then you can match and destruct like this

handle(#msg{to=void, no=3, data=Data}, State) ->
    do_stuff(Data).


Matching records can be a hassle when they are large. The way I deal with it is by testing the first element of the record, which should be the record name:

handle(Whatever) when element(1,Msg) == msg

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜