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
精彩评论