差异确定并结束[Erlang]

时间:2014-11-13 23:55:17

标签: erlang

在Erlang中以end和ok结束函数有什么区别?我一直试图掌握以下代码中的含义:

-module(esOne).
-export([start/1, func/1]).

start(Par) ->
    io:format("Client: I am ~p, spawned by the server: ~p~n",[self(),Par]),
    spawn(esOne, func, [self()]),
    Par ! {onPid, self()},
    serverEsOne ! {onName, self()},
    receiveMessage(),
    ok.

receiveMessage() ->
    receive
        {reply, N} ->
            io:format("Client: I received a message: ~p~n",[N])
    after
        5000->
            io:format("Client: I received no message, i quit~n",[])
    end.

func(Parent)->
    io:format("Child: I am ~p, spawned from ~p~n",[self(),Parent]).

此代码与另一个充当服务器的.erl文件一起使用。我设法写这个只是通过分析给定的服务器文件并复制它的行为。首先我认为ok用于结束每个函数,但事实并非如此,因为我无法使用ok结束receiveMessage()。然后我想我可以用end结束每个函数,但是如果我用end替换ok,start(Par)将会出错。不仅如此,但在服务器文件中,我看到ok和end在函数内用于结束循环。他们使用的方式对我来说看起来是一样的,但他们显然完成了一个单独的功能,因为一个人不能被另一个人取代。一些澄清将非常感激。

1 个答案:

答案 0 :(得分:4)

要理解两点:

  • Erlang中的某些代码块类型以" end"关闭。所以if ... endcond ... endreceive ... [after N] ... end等等。当然可以使用" end"作为自己的原子代替OK,但这不是上面发生的事情。

  • Erlang中的每个函数都返回一些值。如果您没有明确说明它,它将返回最后一个表达式的值。 " ="运算符不像其他语言那样赋值给变量,它在数学中赋值给符号,这意味着重新分配实际上是逻辑断言。如果断言失败,则进程抛出异常(通常意味着它崩溃)。

当你以" ok"结束某事时或者您提供已知最终值的任何其他原子将被返回。你不必对它做任何事情,但如果你想让调用过程声明函数已完成或崩溃,如果发生任何异常,那么你可以:

do_stuff() ->
    ok = some_func().

而不是

do_stuff() ->
    some_func().

如果some_func()可能有副作用可能会失败,它通常会返回ok{error, Reason}(或类似的东西)。通过检查返回值是ok,我们阻止调用进程在发生错误时继续执行。这是Erlang概念的核心,让它崩溃"。基本的想法是,如果你调用一个具有副作用的函数并且它会做任何意想不到的事情,你应该立即崩溃,因为继续处理坏数据比完全不进行更糟糕。崩溃将由主管清理,系统将恢复到已知状态,而不是在副作用失败后留下任何随机情况。

以上位的变化是" ok"如果函数的目的是返回一个值,则部分出现在元组中。例如,您可以在任何dict类型处理库中看到这一点。某些数据返回函数的返回类型为{ok, Value} | {error, Reason}而非Value | {error, Reason}的原因是为了使模式匹配更自然。

考虑以下案例条款:

case dict:find(Key, Dict) of
    {ok, Value} ->
        Value;
    {error, Reason} ->
        log(error, Reason),
        error
end.

case finder(Key, Struct) of
    Value ->
        Value;
    {error, Reason}
        log(error, Reason),
        error
end.

在第一个示例中,我们首先匹配成功条件。但是在第二个版本中,这是不可能的,因为错误子句永远不会匹配;任何回报都将始终由Value表示。糟糕。

返回值崩溃的大多数时间(但并不总是)函数将仅返回值。对于没有状态的纯函数尤其如此,但传入的内容并没有副作用(例如,dict:fetch/2直接给出值,或者使调用进程崩溃,让您可以轻松选择所需的方式做事)。返回值或发出错误信号的函数通常会在{ok, Value}中包含有效响应,因此很容易匹配。