Kir*_*ill 30 erlang callback erlang-otp
正如我从"Erlang and OTP in action"一书中所理解的那样,行为一词指的是:
题:
Erlang/OTP初学者应该了解哪些行为?是否有可能简单地描述和理解OTP行为的概念?
什么'回调函数'在Elang/OTP的上下文中实际意味着什么?
我们可以考虑行为实现中的回调,因为Java中的方法会覆盖吗?
该书说,以下代码中库函数'gen_server:start_link/4'的关联回调函数是'Module:init/1'.
这是否意味着使用init/1我们调用gen_server:start_link/4库函数?或者这意味着什么呢?
-module(tr_server).
-behaviour(gen_server).
-include_lib("eunit/include/eunit.hrl").
%% API
-export([
start_link/1,
start_link/0,
get_count/0,
stop/0
]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-define(DEFAULT_PORT, 1055).
-record(state, {port, lsock, request_count = 0}).
%%%===================================================================
%%% API
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc Starts the server.
%%
%% @spec start_link(Port::integer()) -> {ok, Pid}
%% where
%% Pid = pid()
%% @end
%%--------------------------------------------------------------------
start_link(Port) ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []).
%% @spec start_link() -> {ok, Pid}
%% @doc Calls `start_link(Port)' using the default port.
s tart_link() ->
start_link(?DEFAULT_PORT).
%%--------------------------------------------------------------------
%% @doc Fetches the number of requests made to this server.
%% @spec get_count() -> {ok, Count}
%% where
%% Count = integer()
%% @end
%%--------------------------------------------------------------------
get_count() ->
gen_server:call(?SERVER, get_count).
%%--------------------------------------------------------------------
%% @doc Stops the server.
%% @spec stop() -> ok
%% @end
%%--------------------------------------------------------------------
stop() ->
gen_server:cast(?SERVER, stop).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
init([Port]) ->
{ok, LSock} = gen_tcp:listen(Port, [{active, true}]),
{ok, #state{port = Port, lsock = LSock}, 0}.
handle_call(get_count, _From, State) ->
{reply, {ok, State#state.request_count}, State}.
handle_cast(stop, State) ->
{stop, normal, State}.
handle_info({tcp, Socket, RawData}, State) ->
do_rpc(Socket, RawData),
RequestCount = State#state.request_count,
{noreply, State#state{request_count = RequestCount + 1}};
handle_info(timeout, #state{lsock = LSock} = State) ->
{ok, _Sock} = gen_tcp:accept(LSock),
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%%===================================================================
%%% Internal functions
%%%===================================================================
do_rpc(Socket, RawData) ->
try
{M, F, A} = split_out_mfa(RawData),
Result = apply(M, F, A),
gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Result]))
catch
_Class:Err ->
gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Err]))
end.
split_out_mfa(RawData) ->
MFA = re:replace(RawData, "\r\n$", "", [{return, list}]),
{match, [M, F, A]} =
re:run(MFA,
"(.*):(.*)\s*\\((.*)\s*\\)\s*.\s*$",
[{capture, [1,2,3], list}, ungreedy]),
{list_to_atom(M), list_to_atom(F), args_to_terms(A)}.
args_to_terms(RawArgs) ->
{ok, Toks, _Line} = erl_scan:string("[" ++ RawArgs ++ "]. ", 1),
{ok, Args} = erl_parse:parse_term(Toks),
Args.
%% test
start_test() ->
{ok, _} = tr_server:start_link(1055).
Run Code Online (Sandbox Code Playgroud)
Ste*_*ski 21
我将尝试用简单的术语解释行为背后的基础知识,并让您在理解这些基础知识的基础上回答自己的问题,而不是像其他答案那样尝试解决您的具体问题.
行为基本上是一个消息处理框架,其中"框架"是指可以由最终用户完成和定制的问题的部分解决方案的经典定义.OTP行为基本上提供:
行为将消息处理委托给回调模块,或者将行为实现委托为"Erlang和OTP In Action"来调用它们.在调用其init/1函数时,回调模块通常为消息循环创建状态以代表它.然后,行为循环将此状态传递给回调模块消息处理函数的每个后续调用,并且这些调用中的每一个都可以返回修改后的状态.回调函数还返回指令,告诉行为消息循环下一步做什么.
以下是行为核心的消息循环的大大简化版本:
loop(Callbacks, State) ->
{Next, NState} =? receive
M1 ->?
Callbacks:handle_m1(M1,State);
M2 ->
Callbacks:handle_m2(M2,State);
Other ->
Callbacks:handle_other(Other,State)
end,
case Next of?
stop -> ok;
_ -> loop(Callbacks, NState)
end.Run Code Online (Sandbox Code Playgroud)
这个尾递归循环将Callbacks模块和State变量作为参数.在首次调用此循环之前,您已经告诉行为您的回调模块是什么,然后基本OTP行为支持代码已经调用了您的init/1回调函数来获取初始值State.
我们的例子中行为环接收形式的消息M1,M2以及任何其他信息,其细节不物质这里,对于每个消息,调用在不同的回调函数Callbacks模块.在这个例子中,handle_m1并handle_m2回调函数处理消息M1,并M2分别,而回调handle_other处理所有其他种类的消息.请注意,它State被传递给每个回调函数.每个函数都要返回一个元组,第一个元素告诉循环下一步该做什么,第二个元素包含循环的可能新状态State- 循环存储在变量中的相同值或新的不同值NState.在这个例子中,如果Next是原子stop,则循环停止,但如果它是其他任何东西,则循环以递归方式调用自身,将新状态传递NState给下一次迭代.由于它是尾递归的,所以循环不会吹出堆栈.
如果你仔细研究标准OTP行为的来源,比如gen_server和gen_fsm,你会发现一个类似于此的循环,但由于处理系统消息,超时,跟踪,异常等,它们会更加复杂.标准行为也会启动它们在一个单独的进程中循环,因此它们还包含用于启动循环过程并将消息传递给它的代码.
Aru*_*nmu 19
问: Erlang/OTP初学者应该了解哪些行为?是否有可能简单地描述和理解OTP行为的概念?
行为通常在代码中使用,以便编译器可以根据其行为生成更直观的错误消息,即application/supervisor/gen_server/gen_event/gen_fsm.
它使编译器能够提供特定于ex:gen_server行为的错误消息
问:在Elang/OTP环境中,"回调函数"实际上意味着什么?
可以说回调函数取自GUI编程(至少类似).每当事件发生在前.鼠标单击有一个单独的功能,可以处理鼠标点击.
因此,无论何时例如.从另一个模块调用gen_server的导出函数,该函数可以具有具有不同模式的回调函数(handle_call/handle_cast).
问:我们可以将行为实现中的回调视为在Java中重写的方法吗?
是啊......也许......不:)
问:本书说下面代码中库函数'gen_server:start_link/4'的关联回调函数是'Module:init/1'.
gen_server:start_link自己调用init函数,由w55回答....(对不起,这是一个很大的名字).
希望我已回答你所有的疑问:)
Rob*_*loi 12
Erlang/OTP初学者应该了解哪些行为?
可能是这里写的.
是否有可能简单地描述和理解OTP行为的概念?
从文档中读取:"行为是这些常见模式的形式化.我们的想法是在通用部分(行为模块)和特定部分(回调模块)中划分流程的代码."
什么'回调函数'在Elang/OTP的上下文中实际意味着什么?
请查看上面的链接,其中提供了回调函数的示例.
我们可以考虑行为实现中的回调,因为Java中的方法会覆盖吗?
在Java术语中,行为可能是Java接口,而回调则是接口中定义的方法之一的实现.
该书说,以下代码中库函数'gen_server:start_link/4'的关联回调函数是'Module:init/1'.这是否意味着使用init/1我们调用gen_server:start_link/4库函数?或者这意味着什么呢?
这意味着,每次调用gen_server:start_link/4时,都会调用函数Module:init/1,其中Module是传递给start_link函数的第二个参数,其中您提供的参数为第四个参数.换句话说,这是start_link/4幕后发生的事情:
...
start_link(Name, Module, Args, Opts) ->
...
Module:init(Args)
...
...
Run Code Online (Sandbox Code Playgroud)