1.简介

Gen_fsm是一个通用的有限状态机,它描述了这样的一组关系:
State(S) x Event(E) -> Actions(A),State(S')
这个关系意味着:如果在S状态下发生事件E,将执行动作A并返回状态S'.对于一个FSM实现可以使用gen_fsm行为来实现,它提供了标准的接口函数和回调函数。并且,gen_fsm进程可以安装在supervisor监控树中。回调函数与导出函数的关系如下:
  1.  gen_fsm moduleCallbackmodule
    -----------------------------
    gen_fsm:start_link ----->Module:init/1
    gen_fsm:send_event ----->Module:StateName/2
    gen_fsm:send_all_state_event ----->Module:handle_event/3
    gen_fsm:sync_send_event ----->Module:StateName/3
    gen_fsm:sync_send_all_state_event ----->Module:handle_sync_event/4
    ------>Module:handle_info/3
    ------>Module:terminate/3
    ------>Module:code_change/4

如果回调函数失败或返回坏的值,gen_fsm将会终止。

gen_fsm处理系统消息记录记录在sys模块中(sys模块可以用来调试gen_fsm)。

注意:gen_fsm不会主动的捕获退出信号,必须在回调函数初始化时被指定。process_flag(trap_exit, true).

如果指定的gen_fsm不存在或给与的参数不正确,模块里的所有函数将失败。

如果回调函数返回'hibernate',gen_fsm进程将进入hibernate状态。如果服务器长时间处于空闲状态这可能非常有用。然而应该非常小心的使用这个特征,因为它意味着至少有垃圾回收器,当调用一个忙碌的状态机时,你不能做你想做的事情(会因为垃圾回收而导致状态机停滞)。

2.函数

2.1导出函数
start_link(Module, Args, Options) -> Result
start_link(FsmName, Module, Args, Options) -> Result
FsmName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}

Options = [Option]

Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}

Dbgs = [Dbg]

Dbg = trace | log | statistics

| {log_to_file,FileName} | {install,{Func,FuncState}}

SOpts = [SOpt]

SOpt - see erlang:spawn_opt/2,3,4,5

Result = {ok,Pid} | ignore | {error,Error}

 Error = {already_started,Pid} | term()
用于创建一个gen_fsm进程,可以作为监控树的一部分。可以被监控树直接或间接的调用,将确保gen_fsm被链接到监控树。gen_fsm进程调用Module:init/1来初始化。为了确保同步的启动gen_fsm,start_link/3,4直到Module:init/1返回时才返回。
如果FsmName = {local,Name},gen_fsm在本地通过register/2注册为Name.如果FsmName = {global, GlobalName},gen_fsm在全局通过global:register_name/2注册为GlobalName.如果FsmNam = {via, Module, ViaName},gen_fsm通过Module注册为ViaName,同时回调模块Module将导出函数register_name/2, unregister_name/2, whereis_name/1和send/2,其原理同global,因此{via, Module, GlobalName}是一个有效的引用。
如果没有指定name,gen_fsm不被注册。
Args是一个任意的项式,用于作为Module:init/1的参数。
如果option是{timeout, Time}那么gen_fsm有Time毫秒进行初始化,否则,将返回{error, timeout}来终止。
如果option是{debug, Dbgs}那么Dbgs中相应的sys函数将被调用。详情见sys(3).
如果option是{spawn_opt, Sopts}那么通过指定的值列表来产生gen_fsm进程。详见erlang:spawn_opt
  1. link
  2. |{priority, priority_level()}
  3. |{min_heap_size, integer()>=0}
  4. |{min_bin_vheap_size, integer()>=0}
  5. |{fullsweep_after, integer()>=0}
如果gen_fsm被成功的创建和初始化,将返回{ok,Pid},如果已经存在指定FsName的进程,将返回{error,{alredy_started, Pid}}.

如果Module:init/1因为Reason失败,将返回{error,Reason}.如果Module:init/1返回{stop, Reason}或ignore,并且相应的返回{error,Reason}或ignore.

start(Module, Args, Options) -> Result
start(FsmName, Module, Args, Options) -> Result
FsmName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}

Options = [Option]

Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}

Dbgs = [Dbg]

Dbg = trace | log | statistics

| {log_to_file,FileName} | {install,{Func,FuncState}}

SOpts = [term()]

Result = {ok,Pid} | ignore | {error,Error}

 Error = {already_started,Pid} | term()
用于创建一个独立gen_fsm进程,并不是监控树的一部分。参数描述参见start_link/3,4.

send_event(FsmRef, Event) -> ok
FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
向gen_fsm的FsmRef发送一个异步事件,并立即返回ok.gen_fsm将调用Module:StateName/2来处理事件,StateName为当前gen_fsm的状态。
FsmRef可能是:
  • Pid
  • Name,本地注册的gen_fsm
  • {Name,Node}另一个节点上本地注册gen_fsm
  • {global,GlobalName}全局注册的gen_fsm
  • {via,Module,ViaName}通过指定的进程注册的gen_fsm
Event是一个任意的项式,将被作为参数传递给Module:StateName/2处理。
send_all_state_event(FsmRef, Event) -> ok
FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()

向gen_fsm的FsmRef发送一个异步事件并立即返回ok.这个gen_fsm将调用Module:handle_event/3来处理这个事件。
参数描述参见send_event/2.
send_event和send_all_state_event的不同是处理事件的回调函数不同,该函数是在任何状态下都以同样的方式处理事件,只有一个handle_event子句来处理事件。
sync_send_event(FsmRef, Event) -> Reply
sync_send_event(FsmRef, Event, Timeout) -> Reply
FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()

Timeout = int()>0 | infinity

Reply = term()

向gen_fsm的FsmRef发送一个事件然后等待直到reply返回或发生超时,将调用Module:StateName/3来处理事件,StateName是gen_fsm当前的状态名。

参数描述参见send_event/2.

Timeout是一个等待reply返回大于0指定的毫秒数,或指定为infnity.默认是5000毫秒。如果指定时间内未返回reply函数调用失败。

返回值Reply是回调函数Module:StateName/3返回的。

sync_send_all_state_event(FsmRef, Event) -> Reply
sync_send_all_state_event(FsmRef, Event, Timeout) -> Reply
FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()

Timeout = int()>0 | infinity

向gen_fsm的FsmRef发送一个事件然后等待reply的返回或超时。gen_fsm将调用Module:handle_sync_event/4来处理。

参数描述参见send_event/2和sync_send_event/3.

reply(Caller, Reply) -> true
Caller - see below

该函数用于通过gen_fsm向指定的客户端发送返回值,例如sync_send_event/2,3或sync_send_all_state/2,3当其回调函数Module:StateName/3或Module:handle_sync_event/4不能返回值时。

Caller是客户端的From,Reply是一个任意的项式,他将返回给sync_send_event/2,3或sync_send_all_state/2,3.

send_event_after(Time, Event) -> Ref
Time = integer()

Ref = reference()

用于在gen_fsm内部发送一个延迟事件,在Time时间后将触发。立即返回一个引用,它可以用cancel_timer/1来取消该延迟事件。

gen_fsm将调用Module:StateName/2处理该事件,StateName是当gen_fsm在延迟时间到时延迟事件被发送时的状态名字。

Event是任意类型的项式将作为参数传递给Module:StateName/2.

start_timer(Time, Msg) -> Ref
Time = integer()

Ref = reference()

在gen_fsm内部发送一个超时的事件,在Time事件时执行,并立刻返回他的引用,可以通过cancel_timer/1来取消该方法。

gen_fsm将调用Module:StateName/2处理该事件,StateName是发送该超时事件的状态。

Msg是任意类型项式的超时信息{timeout, Ref, Msg},将作为Module:StateName/2的参数信息。

cancel_timer(Ref) -> RemainingTime | false
Ref = reference()

RemainingTime = integer()

gen_fsm调用该函数来取消名称为Ref的内部定时器。

引用Ref是由send_event_after/2和start_timer/2返回。

如果定时器已经超时,但是并没用事件发送,他被作为超时事件被取消,因此该函数的返回不会有错误的计时器事件。

如果Ref指定的是活跃的事件计时器,将返回剩余的时间直到计时器终止前,否则返回false.

enter_loop(Module, Options, StateName, StateData)
enter_loop(Module, Options, StateName, StateData, FsmName)
enter_loop(Module, Options, StateName, StateData, Timeout)
enter_loop(Module, Options, StateName, StateData, FsmName, Timeout)
Options = [Option]

Option = {debug,Dbgs}

Dbgs = [Dbg]

Dbg = trace | log | statistics

| {log_to_file,FileName} | {install,{Func,FuncState}}

FsmName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}

Timeout = int() | infinity

使一个存在的进程变成gen_fsm.没有返回,取而代之的是,调用进程将进入gen_fsm的接受循环成为一个gen_fsm进程。进程必须使用proc_lib来启动该函数.因此通过该函数进行初始化和名字注册。

当要进行一个比gen_fsm更要复杂的初始化过程时,这个函数非常有用。

Module, Options and FsmName与start_link中的意义一样。然而,如果FsmName被指定,在这个函数调用前,这个进程必须被相应地注册。

StateName,StateDate and Timeout的意义与Module:init/1一样。同时,回调模块Module不需要导出init/1方法。

失败情况:通过proc_lib启动函数不能启动该进程时;不能注册指定的FsmName时。

2.2回调函数
Module:init(Args) -> Result
Result = {ok,StateName,StateData} | {ok,StateName,StateData,Timeout}

| {ok,StateName,StateData,hibernate}

| {stop,Reason} | ignore

Timeout = int()>0 | infinity

每当gen_fsm使用gen_fsm:start[_link]/3,4开始时,通过新进程调用该函数来初始化。

Args是启动函数提供的参数。

如果初始化成功,这个函数应该返回{ok, StateName, SateData[,Timeout | hibernate]},SateName是初始的状态名,StateData是初始的状态数据。

如果提供了一个整数的超时值,在Timeout时间内如果没有接受到事件或消息那么超时将发生。超时的表现是通过一个原子timeout被回调函数Modules:StateName/2处理。其默认值是infinity,表示会一直等待下去。

如果hibernate被指定,那么进程将进入hibernate状态等待下一个消息的到达。

如果在初始化期间发生了一些错误,函数应该返回{stop, Reason}或ignore.

Module:StateName(Event, StateData) -> Result
Event = timeout | term()

Result = {next_state,NextStateName,NewStateData}

| {next_state,NextStateName,NewStateData,Timeout}

| {next_state,NextStateName,NewStateData,hibernate}

| {stop,Reason,NewStateData}

Timeout = int()>0 | infinity

这是一个每个可能状态名的一个函数实例。每当gen_fsm接收到由gen_fsm:send_event/2发送过来的事件时,当前状态名StateName的函数实例将被调用来处理这个事件。同时他也处理超时事件。

Event要么是超时发生时的原子timeout,或send_event/2传递过来的。

如果该函数返回{next_state, NextStateName, NewStateData [, Timeout | hibernate]}时,gen_fsm将继续执行同时转变到新的状态NextStateName并更新数据NewStateDate.hibernate和Timeout的描述详见Module:init/1.

如果返回{stop, Reason, NewStateName},gen_fsm将调用Module:terminate(Reason, NewStateData)终止。

Module:handle_event(Event, StateName, StateData) -> Result
Result = {next_state,NextStateName,NewStateData}

| {next_state,NextStateName,NewStateData,Timeout}

| {next_state,NextStateName,NewStateData,hibernate}

| {stop,Reason,NewStateData}

Timeout = int()>0 | infinity

每当gen_fsm接收到由gen_fsm:send_all_state_event/2发送过来的事件时,这个函数将被调用来处理该事件。

参数描述以及返回值描述参见Module:StateName/2.

Module:StateName(Event, From, StateData) -> Result
From = {pid(),Tag}
Result = {reply,Reply,NextStateName,NewStateData}
  | {reply,Reply,NextStateName,NewStateData,Timeout}
  | {reply,Reply,NextStateName,NewStateData,hibernate}
  | {next_state,NextStateName,NewStateData}
  | {next_state,NextStateName,NewStateData,Timeout}
  | {next_state,NextStateName,NewStateData,hibernate}
  | {stop,Reason,Reply,NewStateData} | {stop,Reason,NewStateData}
 Timeout = int()>0 | infinity
 Reason = normal | term()
这是一个每个可能状态名的一个函数实例。每当gen_fsm接收到由gen_fsm:sync_send_event/2发送过来的事件时,当前状态名StateName的函数实例将被调用来处理这个事件。
Event是由sync_send_event的Event参数提供。
From是一个元组{Pid, Tag},Pid是调用sync_send_event/2,3的进程的Pid,Tag是他的唯一标识。
当函数返回{reply, Reply, NextStateName, NewStateName [, Timeout | hibernate]}时,gen_fsm将继续执行同时转变到状态NextStateName,并跟新值到NewStateData.Timeout和hibernate的描述参见Module:init/1.
当函数返回{next_state, NextStateName, NewStateData [, Timeout | hibernate]}时,gen_fsm将继续执行,同时转变到状态NextStateName并更数据到NewStateName.同时必须现实的调用gen_fsm:reply/2来返回数据reply给From.
如果函数返回{stop, Reason, Reply, NewStateData}或{stop, Reason, NewStateNameData}(该情况必须明确的使用gen_fsm:reply/2返回reply)时,gen_fsm将调用Module:terminate(Reason NewStateName)终止。
Module:handle_sync_event(Event, From, StateName, StateData) -> Result
Result = {reply,Reply,NextStateName,NewStateData}

| {reply,Reply,NextStateName,NewStateData,Timeout}

| {reply,Reply,NextStateName,NewStateData,hibernate}

| {next_state,NextStateName,NewStateData}

| {next_state,NextStateName,NewStateData,Timeout}

| {next_state,NextStateName,NewStateData,hibernate}

| {stop,Reason,Reply,NewStateData} | {stop,Reason,NewStateData}

Timeout = int()>0 | infinity

每当gen_fsm接受到由gen_fsm:sync_send_all_state_event/2,3发送过来的事件时,这个函数被调用来处理该事件。

参数详见Module:StateName/3描述。

Module:handle_info(Info, StateName, StateData) -> Result
Result = {next_state,NextStateName,NewStateData}

| {next_state,NextStateName,NewStateData,Timeout}

| {next_state,NextStateName,NewStateData,hibernate}

| {stop,Reason,NewStateData}

当gen_fsm接收到其他消息时(除出去同步或异步事件以及系统消息),该函数被调用来处理该消息。

其他参数以及返回值描述参见Module:StateName/2.

Module:terminate(Reason, StateName, StateData)
Reason = normal | shutdown | {shutdown,term()} | term()

这个函数在gen_fsm终止时被调用。它的作用与Module:init/1相对并可以做一些必要的清理。当他返回gen_fsm因为Reason终止的原因,返回值将被忽略。

如果Reason是term指定的停止原因,StateName就是当前状态,StateData就是当前状态数据。

如果Reason取决于gen_fsm为什么被终止。如果他是因为另一个回调函数返回了stop元组{stop,...},Reason将在那个元组里被指定。如果由于失败导致,Reason是一个错误原因。

如果gen_fsm是监控树的一部分,被他的监控树所终止,Reason = shutdown 要满足以下条件:

  • gen_fsm被设置成可捕获退出信号
  • 监控树的关闭策略是指定Timeout而不是brutal_kill
甚至如果gen_fsm并不是监控树的一部分,如果从其父进程接收到'EXIT'信号这个函数也会被调用,Reason就是'EXIT'信息。

否则,gen_fsm将立即终止。

注意:非normal, shutdown, or {shutdown,Term}的任何其他原因,如gen_fsm的终止是因为error,这些错误将由error_logger:format/2进行报告。

Module:code_change(OldVsn, StateName, StateData, Extra) -> {ok, NextStateName, NewStateData}
OldVsn = Vsn | {down, Vsn}

关于代码的热更新,后续专题会继续介绍。

3.实践

3.1 启动一个gen_fsm
  1.  start_link(Code)->
    %%gen_fsm:start_link({local,?SERVER},?MODULE, lists:reverse(Code),[]).
    gen_fsm:start({local,?SERVER},?MODULE, lists:reverse(Code),[{timeout,1000}]).
    -spec(init(Args:: term())->
    {ok,StateName:: atom(),StateData::#state{}} |
    {ok,StateName:: atom(),StateData::#state{}, timeout() | hibernate} |
    {stop,Reason:: term()}| ignore).
    init(Code)->
    %%timer:sleep(2000),
    %%{stop,Code}.
    %%ignore.
    {ok, unlock,{[],Code}}.
当调用gen_fsm:start开启fsm服务器事,将回调Modules:init/1进行初始化,并初始化状态unlock,以及状态值{[],Code}.
3.2 发送一个事件
  1.  button(Digital)->
    gen_fsm:send_event(?SERVER,{button,Digital}).
    unlock({button,Digital},{SoFar,Code})->
    case[Digital|SoFar] of
    Code->
    io:format("Pass OK!~n"),
    do_unlock(),
    {next_state, open,{[],Code},3000};
    InCompletwhen length(InComplet)< length(Code)->
    io:format("Input:~p,InComplet~p,Code:~p~n",[Digital,[Digital|SoFar],Code]),
    {next_state, unlock,{InComplet,Code}};
    _Worng->
    io:format("ReInput Password!~n"),
    {next_state, unlock,{[],Code}}
    end.
    open(timeout,State)->
    do_lock(),
    timer:sleep(1000),
    %%{stop, normal,State}.
    {next_state, unlock,State}.
发送一个异步事件,然后当前状态对事件进行处理,根据一定的条件进行状态变更,返回{stop, Reason, State}将调用Module:terminate/2进行终止.
  1.  sync_button()->
    gen_fsm:sync_send_event(?SERVER,open).
    %%gen_fsm:sync_send_event(?SERVER,close,1000). unlock(open,_From,State)->
    do_unlock(),
    io:format("~p~p~n",[_From,State]),
    gen_fsm:reply(_From,{ok,"Successfly!"}),
    %%gen_fsm:reply(_From,normal),{stop, normal,State}.
    %%{stop, normal, normal,State}.
    {next_state, close,State,1000}.
    %%Reply= ok,
    %%{reply,Reply, open,State,3000}.
    close(timeout ,State)->
    do_lock(),
    io:format("~p~p~n",["timeout",State]),
    {next_state, open,State,1000}.
发送一个同步事件,当前状态进行处理以后等待返回,返回{reply, Reply, StateName, State},Reply将返回给调用端。返回{next_state, State, State},那么必须在返回之前调用gen_fsm:reply/2显示的返回给调用端。
3.3 发送一个所有状态都能接受的事件
  1.  send(Data)->
    gen_fsm:send_all_state_event(?SERVER,{send,Data}).
    -spec(handle_event(Event:: term(),StateName:: atom(),
    StateData::#state{}) ->
    {next_state,NextStateName:: atom(),NewStateData::#state{}} |
    {next_state,NextStateName:: atom(),NewStateData::#state{},
    timeout()| hibernate}|
    {stop,Reason:: term(),NewStateData::#state{}}).
    handle_event({send,Data},StateName,State)->
    io:format("Send Data:~p,StateName:~p,State,~p~n",[Data,StateName,State]),
    {next_state,StateName,State}.
向所有的状态发送一个异步的事件,并由handle_event/3进行处理。
  1.  sync_send(Data)->
    Res= gen_fsm:sync_send_all_state_event(?SERVER,{send,Data}),
    io:format("~p~n",[Res]).
    handle_sync_event({send,Data},_From,StateName,State)->
    timer:sleep(2000),
    gen_fsm:reply(_From,{Data,StateName,State,_From}),
    {next_state, open,State,1000}.
    %%{reply,{Data,StateName,State,_From}, open,State,1000}.
    %%{reply,{Data,StateName,State,_From},StateName,State}.
向所有的状态发送一个同步事件,并由handle_sync_event/4进行处理,并向调用端返回Reply,如果返回{next_state, StateName, State}必须显示调用gen_fsm:reply/2向调用端返回。
3.4 开启一个定时器
  1.  unlock(open,_From,State)->
    do_unlock(),
    %%gen_fsm:send_event_after(2500,{button,48}),
    Ref= gen_fsm:start_timer(1500,"start_timer"),
    io:format("~p~p~n",[_From,State]),
    gen_fsm:reply(_From,{ok,"Successfly!"}),
    proc_lib:spawn(fun()->
    timer:sleep(2000),
    Time= gen_fsm:cancel_timer(Ref),
    io:format("RemainTime:~p~n",[Time])
    end),
    %%gen_fsm:reply(_From,normal),{stop, normal,State}.
    %%{stop, normal, normal,State}.
    {next_state, close,State,1000}.
    %%Reply= ok,
    %%{reply,Reply, open,State,3000}.
send_event_after/2表示在指定时间后发送事件,start_timer/2表示在指定事件后发送一个超时事件{timeout, Ref, Msg},但同时可以用cancel_timer/1来结束定时器。
3.5 将普通进程转变为gen_fsm进程
  1.  -spec(start_link()->{ok, pid()}| ignore |{error,Reason:: term()}).
    start_link()->
    io:format("start_link~n"),
    proc_lib:start_link(?MODULE, start_loop,[self()]).
    %%gen_fsm:start_link({local,?SERVER},?MODULE,[],[]).
    start_loop(Person)->
    io:format("start_loop~n"),
    proc_lib:init_ack(Person,self()),
    register(?MODULE,self()),
    gen_fsm:enter_loop(?MODULE,[], state_name,#state{}, {local, ?MODULE}).
通过gen_fsm:enter_loop将一个普通的进程转变为gen_fsm进程。同时不必导出Module:init/1回调函数。适用于比init:/1要更复杂的初始化的处理。

4.总结

gen_fsm实现了通用的有限状态机(FSM),对与在多种状态间的变更处理非常的有用,比如文本解析,模式匹配、游戏逻辑等等方面的处理都是它的强项,所以这个behaviour非常之重要,gen_fsm提供了简便的接口与回调函数来构建有限状态机,根据不同的返回参数在不同的状态间进行切换,也具备了同步或异步事件的处理。
 
 
优秀的代码是艺术品,它需要精雕细琢!

Gen_fsm行为实践与分析的更多相关文章

  1. C++ Primer 学习笔记_46_STL实践与分析(20)--容器特有的算法

    STL实践与分析 --容器特有的算法 与其它顺序容器所支持的操作相比,标准库为list容器定义了更精细的操作集合,使它不必仅仅依赖于泛型操作.当中非常大的一个原因就是list容器不是依照内存中的顺序进 ...

  2. C++ Primer 学习笔记_32_STL实践与分析(6) --再谈string类型(下)

    STL实践与分析 --再谈string类型(下) 四.string类型的查找操作 string类型提供了6种查找函数,每种函数以不同形式的find命名.这些操作所有返回string::size_typ ...

  3. C++ Primer 学习笔记_44_STL实践与分析(18)--再谈迭代器【下】

    STL实践与分析 --再谈迭代器[下] 三.反向迭代器[续:习题] //P355 习题11.19 int main() { vector<int> iVec; for (vector< ...

  4. C++ Primer 学习笔记_40_STL实践与分析(14)--概要、先来看看算法【上】

    STL实践与分析 --概述.初窥算法[上]     标准库容器定义的操作很少.并没有给容器加入大量的功能函数.而是选择提供一组算法,这些算法大都不依赖特定的容器类型,是"泛型"的. ...

  5. C++ Primer 学习笔记_45_STL实践与分析(19)--建筑常规算法

    STL实践与分析 --泛型算法的结构 引言: 正如全部的容器都建立在一致的设计模式上一样,算法也具有共同的设计基础. 算法最主要的性质是须要使用的迭代器种类.全部算法都指定了它的每一个迭代器形參可使用 ...

  6. C++ Primer 学习笔记_33_STL实践与分析(7) --容器适配器

    STL实践与分析 --容器适配器 引: 除了顺序容器.标准库还提供了三种顺序容器适配器:queue,priority_queue和stack.适配器是标准库中的概念.包含容器适配器,迭代器适配器和函数 ...

  7. C++ Primer 学习笔记_35_STL实践与分析(9)--map种类(在)

    STL实践与分析 --map类型(上) 引: map是键-值对的集合. map类型通常能够理解为关联数组:能够通过使用键作为下标来获取一个值,正如内置数组类型一样:而关联的本质在于元素的值与某个特定的 ...

  8. C++ Primer 学习笔记_41_STL实践与分析(15)--先来看看算法【下一个】

    STL实践与分析 --初窥算法[下] 一.写容器元素的算法 一些算法写入元素值.在使用这些算法写元素时一定要当心.必须.写入输入序列的元素 写入到输入序列的算法本质上是安全的--仅仅会写入与指定输入范 ...

  9. C++ Primer 学习笔记_38_STL实践与分析(12)--集成的应用程序容器:文本查询程序

    STL实践与分析 --容器的综合应用:文本查询程序 引言: 本章中最重点的实例.由于不须要用到multiset与multimap的内容.于是将这一小节提到了前面.通过这个实例程序,大师分析问题的智慧, ...

随机推荐

  1. Kinetic使用注意点--group

    new Group(config) 参数: config:包含所有配置项的对象. { x: "横坐标", y: "纵坐标", width: "宽度&q ...

  2. 黑马程序员 SaveFileDialog的跨线程调用 (专题三)

    <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IO开发S</a> ...

  3. Java内存区域与内存溢出异常(二)

    了解Java虚拟机的运行时数据区之后,大致知道了虚拟机内存的概况,内存中都放了些什么,接下来将了解内存中数据的其他细节,如何创建.如何布局.如何访问.这里虚拟机以HotSpot为例,内存区域以Java ...

  4. c# 赋值后最后一项数据部分丢失

    赋值,赋值后 原因,在添加后立即调用clear()清除数据....

  5. IOS项目集成ShareSDK实现第三方登录、分享、关注等功能(备用)

    (1)官方下载ShareSDK iOS 2.8.8,地址:http://sharesdk.cn/ (2)根据实际情况,引入相关的库,参考官方文档. (3)在项目的AppDelegate中一般情况下有三 ...

  6. 转载:传说中的T检验

    第二周结束:传说中的T检验 小耿2014-01-21 10:58 本文和上一篇笔记一样:语言十分啰嗦.请大家忍耐…… 以前我不懂统计的时候(现在也不懂),只知道数据出来了要做三件事:1,检验一下数据是 ...

  7. Contest2037 - CSU Monthly 2013 Oct (Problem J: Scholarship)

    http://acm.csu.edu.cn/OnlineJudge/problem.php?cid=2037&pid=9 [题解]: 这题卡了一下,卡在负数的情况,负数输出 0 这题主要找到一 ...

  8. tcpprep 对IPV6的支持

    在采用tcpreplay对包实施回放前,需要对包执行预处理,tcpprep就是完成这个任务的.tcpprep要做的处理就是生成一个cache文件,根据tcpprep wiki的介绍http://tcp ...

  9. 如果Android和C#在一起?

    先看两则新闻.   一则来自新浪科技:   谷歌上诉遭拒绝 需向甲骨文支付Java使用费 大意是说,针对谷歌Android操作系统侵犯甲骨文Java知识产权的指控,美国法院最近做出了有利于甲骨文的裁决 ...

  10. 4.0 spring-注册解析的Bean

    1.0 registerBeanDefinition 对于配置文件,解析也解析完了,装饰也装饰完了,对于得到的BeanDefinition已经可以满足后续的使用了,唯一剩下的工作就是注册了, 也就是: ...