在函数调用中隐藏状态

时间:2015-04-14 07:53:47

标签: erlang

我在考虑函数调用时隐藏状态。 例如:

body_to_client(Req, ClientRef) ->
  case cowboy_req:body(Req) of
    {ok, Data, Req2} ->
      ok = hackney:send_body(ClientRef, Data),
      Req2;
    {more, Data, Req2} ->
      ok = hackney:send_body(ClientRef, Data),
      body_to_client(Req2, ClientRef)
  end.

但我想将这些代码分成几个部分并隐藏实现:

body_to_client(ReadRequestBody, ClientRef) ->
  case ReadRequestBody() of
    {ok, Data} ->
      ok = hackney:send_body(ClientRef, Data),
      ReadRequestBody;
    {more, Data} ->
      ok = hackney:send_body(ClientRef, Data),
      body_to_client(ReadRequestBody, ClientRef)
  end.

其中ReadRequestBody是包含所有细节和状态的函数。 我认为它应该是这样的:

ReadRequestBody = fun() ->
    {Status, Data, Req2} = cowboy_req:body(Req),
    {Status, Data}
  end

但我不知道如何处理Req2并在下次通话中传递它。

1 个答案:

答案 0 :(得分:4)

提取Req2的唯一方法是使用ReadRequestBody的其余结果返回它:

ReadRequestBody = fun() ->
    {Status, Data, Req2} = cowboy_req:body(Req),
    {{Status, Data}, Req2}
  end

然后你必须检查,就像你之前做的那样,但是现在有了更多的语法,你不需要一个闭包,还有几行来分割结果并匹配它的内容,等等.HOIR ON火!啊!让我们把音量提高一个档次......

我觉得整件事情只是变得越来越复杂,所以可能会转向另一个方向,删除聪明的设备而不是添加它们,揭示了一些东西。让我们看看没有case的情况:

body_to_client({ok, Data, Req}, ClientRef) ->
    ok = hackney:send_body(ClientRef, Data),
    Req;
body_to_client({more, Data, Req}, ClientRef) ->
    ok = hackney:send_body(ClientRef, Data),
    body_to_client(cowboy_req:body(Req), ClientRef).

现在body_to_client/2是一个自己的命名案例。但是我们两次都做同样的事情(总是把数据发送到ClientRef),写两次感觉很傻。关于是否要迭代,实际上只有一个决策点。让我们提炼出来:

body_to_client({Status, Data, Req}, ClientRef) ->
    ok = hackney:send_body(ClientRef, Data),
    check_status({Status, Req} ClientRef).

check_status({ok, Req}, _) ->
    Req;
check_status({more, Req}, ClientRef) ->
    body_to_client(cowboy_req:body(Req), ClientRef).

现在一切都已命名,代码明确了每件作品的作用。如果check_status/2看起来更具可读性,我们可以将body_to_client/2作为case传回[{1}}:

body_to_client({Status, Data, Req}, ClientRef) ->
    ok = hackney:send_body(ClientRef, Data),
    case Status of
        ok   -> Req;
        more -> body_to_client(cowboy_req:body(Req), ClientRef)
    end.

请注意,将作为命名函数正常工作的匹配作为case引入另一个函数是有争议的。名称body_to_client现在有点谎言,因为这个功能不仅仅是将主体发送到客户端(但这个谎言的性质可能也可能不重要,具体取决于代码的其余部分)。