【问题标题】:Unable to use function call in function guard无法在函数保护中使用函数调用
【发布时间】:2013-07-28 15:56:20
【问题描述】:

我是 Erlang 新手,正在尝试编写一个有界缓冲区问题程序。它几乎可以工作,除了确保生产者不会领先太多并覆盖未使用的数据。为了解决这个问题,我决定尝试在我的 buffer() 函数上设置保护,这样当缓冲区已满时我可以有一个不使用接收的版本,当缓冲区为空时使用一个不带发送的版本,以及一个正常的其余时间的版本。

我的问题是无接收器版本的保护要求我知道表示缓冲区的数组的大小,这需要调用array:size/1。显然,Erlang 不允许在守卫中调用函数,这阻止了它的工作。有没有办法在不改变我的缓冲区演员的函数声明的情况下解决这个问题?

%% buffer: array num num
%% A process that holds the shared buffer for the producers and consumers
buffer(Buf, NextWrite, NextRead) when NextWrite == NextRead ->
    io:format(" * ~w, ~w, ~w~n", [array:to_list(Buf), NextRead, NextWrite]),
    receive
        {enqueue, Reply_Pid, Num} ->
            io:format("~w: > ~w~n", [Reply_Pid, Num]),
            buffer(array:set(NextWrite rem array:size(Buf), Num, Buf), NextWrite + 1, NextRead);
        finish ->
            io:format("finished printing~n")
    end;
buffer(Buf, NextWrite, NextRead) when (NextWrite - NextRead) == array:size(Buf) ->
    io:format(" * ~w, ~w, ~w~n", [array:to_list(Buf), NextRead, NextWrite]),
    receive
        {dequeue, Reply_Pid} ->
            io:format("~w: < ~w~n", [Reply_Pid, array:get(NextRead rem array:size(Buf), Buf)]),
            Reply_Pid ! {reply, array:get(NextRead rem array:size(Buf), Buf)},
            buffer(Buf, NextWrite, NextRead + 1);
        finish ->
            io:format("finished printing~n")
    end;
buffer(Buf, NextWrite, NextRead) ->
    io:format(" * ~w, ~w, ~w~n", [array:to_list(Buf), NextRead, NextWrite]),
    receive
        {dequeue, Reply_Pid} ->
            io:format("~w: < ~w~n", [Reply_Pid, array:get(NextRead rem array:size(Buf), Buf)]),
            Reply_Pid ! {reply, array:get(NextRead rem array:size(Buf), Buf)},
            buffer(Buf, NextWrite, NextRead + 1);
        {enqueue, Reply_Pid, Num} ->
            io:format("~w: > ~w~n", [Reply_Pid, Num]),
            buffer(array:set(NextWrite rem array:size(Buf), Num, Buf), NextWrite + 1, NextRead);
        finish ->
            io:format("finished printing~n")
    end.

【问题讨论】:

    标签: erlang


    【解决方案1】:

    只有某些功能可以在警卫中使用,请参阅Guard Sequences in the Erlang manual。您可以轻松地做您需要的事情,如下所示:

    buffer(Buf, NextWrite, NextRead) -> buffer(Buf, NextWrite, NextRead, array:size(Buf)).
    
    buffer(Buf, NextWrite, NextRead, _) when NextWrite == NextRead -> 
      ;
    buffer(Buf, NextWrite, NextRead, BufSize) when (NextWrite - NextRead) == BufSize ->
      ;
    buffer(Buf, NextWrite, NextRead, _) ->
      .
    

    【讨论】:

    • 这很好,简单且易于理解。谢谢。
    • 嗨@Geoff,你知道一种比较两个字符串作为警卫的方法吗?例如 - string:equals(string1, string2) -> 1 时的函数。
    • @DenisWeerasiri 我很确定string:equals/2== 是一样的,所以你可以在守卫中使用它。
    【解决方案2】:

    正如 Geoff Reedy 所提到的,只有少数 BIFS 可以在警卫中使用。

    但是guardian解析转换库可以用来调用守卫中的任何函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-03
      • 2014-11-03
      • 1970-01-01
      • 2014-05-08
      • 2020-08-10
      • 1970-01-01
      • 2017-12-12
      • 2011-08-08
      相关资源
      最近更新 更多