差异确定并结束 [Erlang]

Bab*_*ger 4 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]).
Run Code Online (Sandbox Code Playgroud)

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

zxq*_*xq9 6

两点理解:

  • Erlang 中的一些代码块类型以“结束”结束。所以if ... end, case ... end,receive ... [after N] ... end等等。当然可以使用“end”作为它自己的原子来代替 OK,但这不是上面发生的事情。

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

当您以“ok”或任何其他原子结束某事时,您将提供将返回的已知最终值。您不必对它做任何事情,但是如果您希望调用过程断言该函数已完成或在发生任何异常时崩溃,那么您可以:

do_stuff() ->
    ok = some_func().
Run Code Online (Sandbox Code Playgroud)

代替

do_stuff() ->
    some_func().
Run Code Online (Sandbox Code Playgroud)

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

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

考虑以下 case 子句:

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

和:

case finder(Key, Struct) of
    Value ->
        Value;
    {error, Reason}
        log(error, Reason),
        error
end.
Run Code Online (Sandbox Code Playgroud)

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

大多数情况下(但并非总是如此)返回值崩溃的函数将仅返回该值。对于不携带状态但传递的内容且没有副作用的纯函数尤其如此(例如,dict:fetch/2直接给出值,或使调用过程崩溃,让您可以轻松选择想要做事的方式)。返回值或发出错误信号的函数通常包含有效响应,{ok, Value}因此很容易匹配。

  • @Babyburger 基本上,你明白了。但请记住,`ok` 是实际的返回值,所以它更像是 Java 中的 `return "ok";`。否则,该值将是函数中最后一个表达式返回的任何值。在 Erlang 中执行 `ok = somefun()` 就像在 Java 中用 `if (somefun() != "ok") {throw new SomeException;}` 调用它,而在 Erlang 中调用 `somefun(),` 就像只是在 Java 中调用 `somefun();`,然后让返回值进入垃圾箱。无论如何,您都在正确的轨道上。稍微玩弄一下 Erlang,一切都会突然变得如此明显。:-) (2认同)