【问题标题】:Erlang, why does it not have global variables and records?Erlang,为什么它没有全局变量和记录?
【发布时间】:2014-02-13 07:03:29
【问题描述】:

我现在在 Erlang 做一个实验室,这是我第一次编写 Erlang。我有一个 initial_state 函数,它应该在聊天程序中为客户端设置初始状态。但是,如果您没有任何东西可以像在 Java 或 C 中那样存储它,那么设置这个初始状态有什么意义呢?我的意思是感觉就像我只是在创建初始状态然后将其丢弃。那有什么意义呢?我想在某个地方存放它,以便以后使用。

initial_state(Nick, GUIName) -> #cl_st { gui = GUIName }。

【问题讨论】:

  • 在提出此类问题之前,您是否尝试阅读任何教程?
  • 将状态传递给所有需要它的东西。这在 Java / C 中也很好。

标签: erlang


【解决方案1】:

您的问题缺少一些上下文,让整个模块给出一个好的答案可能会很有用。

无论如何,你展示的函数很简单,它是一个返回客户端状态记录的函数,其中 gui 字段等于 GUIName。

这个函数看起来很奇怪,因为它有2个参数,而且参数Nick没有使用。

在erlang中只有局部变量,它们属于一个进程,不能与另一个进程共享。这意味着两件事:

  • 如果你想跟踪一个变量值,它所属的进程一定不能死,所以它必须是递归的。
  • 如果你想在进程之间进行交换,你必须使用消息

通常将服务器拆分为一个 init 函数、一些回调和接口函数以及一个无限循环。我想这是对 OTP 的 gen_server 行为的一个很好的介绍。我可以想象以这种方式补充您的代码:

%% the record state definition, it will include
%% the client nickname,
%% the gui name (or pid ?)
%% the client cart with a default value equals to the empty list
-record(cl_st,{nick,gui,cart=[]}).

initial_state(Nick, GUIName) -> 
%% the role of this function could be to start processes such as the gui
%% and return the initial state
    %% add some code to start the gui
    #cl_st { gui = GUIName, nick = Nick}.

%% an example of an interface function to add some item to the client cart
%% it simply pack the parameters into a tuple and send it to the server
%% Note that the server is identified by its pid, so somwhere there must be a unique
%% server that keep the list of all clients and their server pid
add_to_cart(Pid,Item,Price,Quantity) ->
    Pid ! {add_to_cart,Item,Price,Quantity}.

%% this function calls the init function, starts the server in a new process (usage of spawn) with the
%% initial state and returns the server pid 
start(Nick,GUIName) ->
    State = initial_state(Nick, GUIName),
    spawn(?MODULE,cl_loop,[State]).

stop(Pid) ->
    Pid ! stop.

%% the server loop
%% this example manages 2 kind of messages
cl_loop(State) ->
    receive
        %% add to cart simply builds a tuple made of item, price and quantity and add it to a list
        %% of tuple representing the cart content.
        %% it calls itself recursively with a new state as parameter where the old cart
        %% is replaced by the new one
        {add_to_cart,Item,Price,Quantity} ->
            NewCart = [{Item,Price,Quantity}|State#cl_st.cart],
            cl_loop(State#cl_st{cart=NewCart});
        %% to stop the server, it calls the terminate callback function and does not call itself recursively 
        stop ->
            terminate(State);
        %% other messages are ignored, the server simply calls itself with an unchanged state
        Ignored ->
            cl_loop(State)
    end. 

%% a callback function to terminate the server properly
terminate(State#cl_st{gui = GUIName, nick = Nick}) ->
    %% some code to stop the gui
    {stopped_client, Nick}.

(肯定是代码有问题,我都没编译)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-17
    • 2019-04-01
    • 2011-12-08
    • 2018-04-23
    • 1970-01-01
    • 2014-08-23
    • 2011-01-04
    • 1970-01-01
    相关资源
    最近更新 更多