为什么 gen_fsm 状态方法必须 return 某些东西?

Why do gen_fsm state methods must return something?

我目前正在阅读 LYAE 并且我正在尝试理解为什么 gen_fsm 状态方法必须 return 根据 source

{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}

如果我有 3 种状态方法:abc,谁能给我解释一下,状态机定义如下:

a()->
  receive
    something -> b();
    _ -> error(err)
  end.

b()->
  receive 
    somethingelse-> c();
    _ ->
  end.

为什么我需要下一个状态方法的 return 结果?

someMethod()->
   receive 
      _ -> 
           {next_state, NextStateName, NewStateData}=someNextMethod(),
          //why would i place code here? What could i possibly do with the above tuple ?
   end.

我不明白为什么我要把代码放在之后调用下一个状态方法?所有调用都是递归的,所以除了在 fsm 结束或抛出后我可以实际做一些事情的初始状态之外,为什么我要把代码放在其他状态?

你是对的,不需要 return 值,你必须对某个函数进行递归调用,该函数将等待接收语句:有必要让事情发展(因为不变性变量)并对新消息做出反应。

重点是您的示例是一个模块状态机,而当您使用 gen_fsm 行为时,至少有 2 个模块在起作用:

  • 隐式和通用 gen_fsm 行为模块本身
  • 以及您正在编写的具体回调模块。

每个模块的作用非常不同。

  • 通用的负责保持状态和接收消息(这就是为什么你不能在你的代码中处理这个),它提供不同类型的消息:同步或异步,一种状态或任何状态,通过 gen_fsm 接口或 "freely sent" 消息...它还管理操作模式:初始化、停止、代码更改...它还在后台管理与 OTP 系统的接口。由于它是一个通用模块,它无法识别您要定义的状态和转换。
  • gen_fsm(几乎)每次收到消息时都会调用回调模块。调用的函数取决于状态和消息。回调模块负责为状态机定义状态和转换,它是通过将 return 值发送回 gen_fsm 来完成的。 return 值包含几个字段,下一个状态是强制性的,因为 gen_fsm 必须知道要进入哪个状态 "go" - 进入状态是图像,它只是存储的状态名称在一个变量中并由主 fsm 循环维护——它还可以维护更多信息(通常也称为状态信息,这是令人困惑的,例如门锁系统的当前密码)。 return 值还可能包含其他内容,例如在同步消息的情况下对调用者的回复、下一条传入消息之前的超时、停止 fsm 的请求...

简而言之,gen_fsm 是一个简单的递归循环,等待 "event" 消息,至少维护 State_name 变量。它使用存储在回调模块中的辅助函数来描述其行为。与您所说的相差无几,但具有通用模块带来的限制 - 以及集成到 OTP 和经过验证的代码的优势。

   {next_state, NextStateName, NewStateData}=someNextMethod(),
   //why would i place code here? What could i possibly do with the above tuple ?

例如:

  {next_state, NextStateName, NewStateData}=someNextMethod(),
  {next_state, NextStateName, NewStateData + 1}

或者:

  {next_state, NextStateName, NewStateData}=someNextMethod(),
  ModifiedStateData = do_calculation(NewStateData),
  {next_state, NextStateName, ModifiedStateData}