Erlang复杂模式匹配 #

一、嵌套模式匹配 #

1.1 嵌套元组 #

erlang
-module(nested_tuple).
-export([extract/1]).

extract({person, Name, {address, {city, City}, {country, Country}}}) ->
    #{name => Name, city => City, country => Country}.

1.2 嵌套列表 #

erlang
-module(nested_list).
-export([process/1]).

process([[H1 | _], [H2 | _] | _]) ->
    {first_heads, H1, H2};
process([Single | _]) ->
    {single, Single};
process([]) ->
    empty.

1.3 混合嵌套 #

erlang
-module(mixed_nested).
-export([handle/1]).

handle({request, 
        {header, Id, Version}, 
        {body, {type, Type}, Data}}) ->
    #{id => Id, version => Version, type => Type, data => Data}.

二、复杂守卫 #

2.1 多条件守卫 #

erlang
-module(multi_guard).
-export([classify/1]).

classify({point, X, Y}) 
    when X > 0, Y > 0 -> first_quadrant;
classify({point, X, Y}) 
    when X < 0, Y > 0 -> second_quadrant;
classify({point, X, Y}) 
    when X < 0, Y < 0 -> third_quadrant;
classify({point, X, Y}) 
    when X > 0, Y < 0 -> fourth_quadrant;
classify({point, 0, 0}) -> origin;
classify({point, _, 0}) -> x_axis;
classify({point, 0, _}) -> y_axis.

2.2 守卫中的orelse #

erlang
-module(guard_orelse).
-export([is_weekend/1]).

is_weekend(Day) when Day =:= saturday; Day =:= sunday -> true;
is_weekend(_) -> false.

2.3 复杂守卫表达式 #

erlang
-module(complex_guard).
-export([validate_user/1]).

-record(user, {name, age, role}).

validate_user(#user{name = Name, age = Age, role = Role}) 
    when is_list(Name), length(Name) > 0,
         Age >= 18, Age =< 120,
         Role =:= admin orelse Role =:= user ->
    valid;
validate_user(_) ->
    invalid.

2.4 守卫函数组合 #

erlang
-module(guard_combine).
-export([process/2]).

process(List, N) 
    when is_list(List), length(List) >= N, N > 0 ->
    lists:sublist(List, N);
process(_, _) ->
    {error, invalid_args}.

三、列表模式进阶 #

3.1 特定长度列表 #

erlang
-module(list_length_pattern).
-export([process/1]).

process([]) -> empty;
process([A]) -> one(A);
process([A, B]) -> two(A, B);
process([A, B, C]) -> three(A, B, C);
process([_, _, _ | _]) -> many.

3.2 前缀匹配 #

erlang
-module(prefix_match).
-export([check/2]).

check([], _) -> true;
check([H | T1], [H | T2]) -> check(T1, T2);
check(_, _) -> false.

3.3 后缀匹配 #

erlang
-module(suffix_match).
-export([ends_with/2]).

ends_with(Suffix, List) ->
    ends_with(lists:reverse(Suffix), lists:reverse(List)).

ends_with([], _) -> true;
ends_with([H | T1], [H | T2]) -> ends_with(T1, T2);
ends_with(_, _) -> false.

3.4 分割列表 #

erlang
-module(split_pattern).
-export([split_at/2]).

split_at(N, List) -> split_at(N, List, []).

split_at(0, List, Acc) -> {lists:reverse(Acc), List};
split_at(_, [], Acc) -> {lists:reverse(Acc), []};
split_at(N, [H | T], Acc) -> split_at(N - 1, T, [H | Acc]).

四、二进制模式进阶 #

4.1 协议解析 #

erlang
-module(protocol_parse).
-export([parse_header/1]).

parse_header(<<Version:4, IHL:4, ToS:8, TotalLength:16,
               Identification:16, Flags:3, FragmentOffset:13,
               TTL:8, Protocol:8, HeaderChecksum:16,
               SourceIP:32, DestIP:32, Rest/binary>>) ->
    #{version => Version,
      ihl => IHL,
      tos => ToS,
      total_length => TotalLength,
      identification => Identification,
      flags => Flags,
      fragment_offset => FragmentOffset,
      ttl => TTL,
      protocol => Protocol,
      checksum => HeaderChecksum,
      source_ip => format_ip(SourceIP),
      dest_ip => format_ip(DestIP),
      payload => Rest}.

format_ip(IP) ->
    <<A, B, C, D>> = <<IP:32>>,
    io_lib:format("~p.~p.~p.~p", [A, B, C, D]).

4.2 变长字段 #

erlang
-module(varlen_field).
-export([parse_message/1]).

parse_message(<<Type:8, Length:16, Data:Length/binary, Rest/binary>>) ->
    #{type => Type, data => Data, rest => Rest};
parse_message(<<Type:8, 0:16>>) ->
    #{type => Type, data => <<>>, rest => <<>>}.

4.3 位级解析 #

erlang
-module(bit_level_parse).
-export([parse_flags/1]).

parse_flags(<<_:5, Urg:1, Ack:1, Psh:1, Rst:1, Syn:1, Fin:1>>) ->
    #{urg => Urg =:= 1,
      ack => Ack =:= 1,
      psh => Psh =:= 1,
      rst => Rst =:= 1,
      syn => Syn =:= 1,
      fin => Fin =:= 1}.

五、映射模式进阶 #

5.1 部分匹配 #

erlang
-module(map_partial).
-export([handle/1]).

handle(#{type := user, name := Name}) ->
    {user, Name};
handle(#{type := admin, name := Name, level := Level}) ->
    {admin, Name, Level};
handle(#{type := Type}) ->
    {unknown, Type}.

5.2 嵌套映射 #

erlang
-module(nested_map).
-export([extract/1]).

extract(#{user := #{name := Name, address := #{city := City}}}) ->
    #{name => Name, city => City}.

5.3 可选字段 #

erlang
-module(optional_field).
-export([process/1]).

process(#{name := Name, email := Email}) ->
    {full, Name, Email};
process(#{name := Name}) ->
    {partial, Name};
process(_) ->
    unknown.

六、函数子句模式 #

6.1 多参数模式 #

erlang
-module(multi_arg_pattern).
-export([process/2]).

process([], _) -> empty_list;
process(_, []) -> empty_second;
process([H1 | _], [H2 | _]) when H1 > H2 -> first_larger;
process([H1 | _], [H2 | _]) when H1 < H2 -> second_larger;
process([H | _], [H | _]) -> equal_heads.

6.2 记录模式 #

erlang
-module(record_pattern).
-export([handle/1]).

-record(user, {name, role = guest}).

handle(#user{role = admin}) -> administrator;
handle(#user{role = moderator}) -> moderator;
handle(#user{role = guest}) -> guest.

6.3 复杂函数头 #

erlang
-module(complex_func_head).
-export([route/3]).

route(get, "/users", _Params) -> list_users;
route(get, ["/users", Id], _Params) -> get_user(Id);
route(post, "/users", Params) -> create_user(Params);
route(put, ["/users", Id], Params) -> update_user(Id, Params);
route(delete, ["/users", Id], _Params) -> delete_user(Id);
route(_, _, _) -> not_found.

list_users() -> ok.
get_user(_Id) -> ok.
create_user(_Params) -> ok.
update_user(_Id, _Params) -> ok.
delete_user(_Id) -> ok.

七、case表达式模式 #

7.1 复杂case #

erlang
-module(complex_case).
-export([process/1]).

process(Data) ->
    case Data of
        {ok, {result, Value}} when Value > 0 ->
            {positive, Value};
        {ok, {result, Value}} when Value < 0 ->
            {negative, Value};
        {ok, {result, 0}} ->
            zero;
        {error, {validation, Field}} ->
            {validation_error, Field};
        {error, Reason} ->
            {error, Reason};
        _ ->
            unknown
    end.

7.2 嵌套case #

erlang
-module(nested_case).
-export([process/1]).

process({request, Type, Data}) ->
    case Type of
        create ->
            case validate(Data) of
                ok -> create_resource(Data);
                {error, Reason} -> {error, Reason}
            end;
        update ->
            case find(Data) of
                {ok, Resource} -> update_resource(Resource, Data);
                {error, Reason} -> {error, Reason}
            end;
        delete ->
            delete_resource(Data)
    end.

validate(_) -> ok.
find(_) -> {ok, resource}.
create_resource(_) -> ok.
update_resource(_, _) -> ok.
delete_resource(_) -> ok.

八、receive模式 #

8.1 选择性接收 #

erlang
-module(selective_receive).
-export([collect/2]).

collect(0, Acc) -> lists:reverse(Acc);
collect(N, Acc) ->
    receive
        {data, Value} ->
            collect(N - 1, [Value | Acc]);
        {error, _Reason} ->
            collect(N, Acc)
    after 5000 ->
        timeout
    end.

8.2 模式优先级 #

erlang
-module(receive_priority).
-export([loop/0]).

loop() ->
    receive
        {urgent, Msg} ->
            handle_urgent(Msg),
            loop();
        {normal, Msg} ->
            handle_normal(Msg),
            loop();
        {low, Msg} ->
            handle_low(Msg),
            loop()
    end.

handle_urgent(Msg) -> io:format("Urgent: ~p~n", [Msg]).
handle_normal(Msg) -> io:format("Normal: ~p~n", [Msg]).
handle_low(Msg) -> io:format("Low: ~p~n", [Msg]).

8.3 超时处理 #

erlang
-module(timeout_receive).
-export([request/2]).

request(Pid, Msg) ->
    Ref = make_ref(),
    Pid ! {request, self(), Ref, Msg},
    receive
        {response, Ref, Result} -> {ok, Result}
    after 5000 ->
        {error, timeout}
    end.

九、实际应用案例 #

9.1 JSON解析 #

erlang
-module(json_pattern).
-export([extract/2]).

extract(Key, {struct, Props}) when is_list(Props) ->
    case proplists:get_value(Key, Props) of
        undefined -> undefined;
        Value -> extract_value(Value)
    end;
extract(Key, {array, Items}) when is_list(Items) ->
    [extract(Key, Item) || Item <- Items];
extract(_, _) ->
    undefined.

extract_value({struct, Props}) -> {struct, Props};
extract_value({array, Items}) -> {array, Items};
extract_value(Value) -> Value.

9.2 HTTP路由 #

erlang
-module(http_router).
-export([route/1]).

route(#{method := get, path := "/"}) ->
    index;
route(#{method := get, path := "/users"}) ->
    list_users;
route(#{method := get, path := "/users/" ++ Id}) ->
    {get_user, Id};
route(#{method := post, path := "/users", body := Body}) ->
    {create_user, Body};
route(#{method := Method, path := Path}) ->
    {not_found, Method, Path}.

9.3 消息协议 #

erlang
-module(message_protocol).
-export([encode/1, decode/1]).

encode({ping, Id}) ->
    <<1:8, Id:32>>;
encode({pong, Id}) ->
    <<2:8, Id:32>>;
encode({data, Id, Data}) when is_binary(Data) ->
    Length = byte_size(Data),
    <<3:8, Id:32, Length:16, Data/binary>>;
encode({error, Id, Code, Msg}) when is_binary(Msg) ->
    Length = byte_size(Msg),
    <<4:8, Id:32, Code:16, Length:8, Msg/binary>>.

decode(<<1:8, Id:32>>) ->
    {ping, Id};
decode(<<2:8, Id:32>>) ->
    {pong, Id};
decode(<<3:8, Id:32, Length:16, Data:Length/binary>>) ->
    {data, Id, Data};
decode(<<4:8, Id:32, Code:16, Length:8, Msg:Length/binary>>) ->
    {error, Id, Code, Msg}.

9.4 状态机 #

erlang
-module(state_machine).
-export([start/0, event/2]).

start() -> idle.

event(idle, connect) -> connected;
event(connected, disconnect) -> idle;
event(connected, {send, Data}) -> 
    io:format("Sending: ~p~n", [Data]),
    connected;
event(State, _Event) -> State.

十、模式匹配最佳实践 #

10.1 保持模式简单 #

erlang
-module(simple_pattern).
-export([good/1, bad/1]).

good({ok, Value}) -> Value;
good({error, Reason}) -> {error, Reason}.

bad({ok, {nested, {deep, {value, Value}}}}) -> Value.

10.2 使用辅助函数 #

erlang
-module(helper_func).
-export([process/1]).

process(Data) ->
    case extract_info(Data) of
        {ok, Info} -> handle_info(Info);
        {error, Reason} -> {error, Reason}
    end.

extract_info({type_a, Value}) -> {ok, {a, Value}};
extract_info({type_b, Value}) -> {ok, {b, Value}};
extract_info(_) -> {error, unknown_type}.

handle_info({a, Value}) -> {processed_a, Value};
handle_info({b, Value}) -> {processed_b, Value}.

10.3 使用记录提高可读性 #

erlang
-module(record_readability).
-export([process/1]).

-record(request, {type, id, data}).

process(#request{type = create, id = Id, data = Data}) ->
    {create, Id, Data};
process(#request{type = update, id = Id, data = Data}) ->
    {update, Id, Data};
process(#request{type = delete, id = Id}) ->
    {delete, Id}.

十一、总结 #

本章学习了:

  • 嵌套模式匹配
  • 复杂守卫表达式
  • 列表模式进阶
  • 二进制模式进阶
  • 映射模式进阶
  • 函数子句模式
  • case和receive模式
  • 实际应用案例
  • 最佳实践

准备好学习控制流了吗?让我们进入下一章。

最后更新:2026-03-27