0

0

如何在Golang中实现状态模式State Go语言有限状态机FSM

P粉602998670

P粉602998670

发布时间:2026-03-16 18:24:44

|

318人浏览过

|

来源于php中文网

原创

State接口应仅定义当前状态合法行为,避免预设所有动作;状态转移由上下文统一调度并加锁;初始化需依赖注入且校验非nil;状态对象应轻量无状态或明确管理生命周期。

如何在golang中实现状态模式state go语言有限状态机fsm

State 接口怎么设计才不踩坑

Go 没有继承,状态模式靠接口组合实现,State 接口不能暴露太多方法,否则每个状态都要实现一堆空方法。常见错误是把所有业务动作(比如 InsertCoinEjectCoinTurnCrank)全塞进接口,结果新增一个状态就要补 10 个空实现。

正确做法是只定义「当前状态能响应什么」——也就是该状态下的合法行为,其他非法操作统一返回错误或 panic。比如售货机空闲时只允许 InsertCoin,那 IdleState 就只实现它,其余方法要么不实现(编译报错提醒你漏了),要么用 panic("illegal transition") 明确拒绝。

  • State 接口只包含当前状态实际需要响应的方法,不要预设所有可能动作
  • 让具体状态结构体只嵌入真正需要的接口(如 coinablecrankable),而不是大而全的 State
  • 避免在接口里放 GetNextState 这类逻辑,状态转移决策应由上下文(如 VendingMachine)控制

状态转移为什么不能在 State 内部做

很多初学者会在 InsertCoin 方法里直接改 machine.currentState = &HasCoinState{},这会导致两个问题:一是状态对象自己修改宿主,耦合过重;二是并发下容易出现竞态——比如两个 goroutine 同时调用 InsertCoin,可能一个刚判断完状态,另一个就已切换,导致逻辑错乱。

状态转移必须由持有状态的主体(如 VendingMachine)统一调度,且要用互斥锁保护 currentState 字段。转移前检查合法性(比如是否允许从当前状态转到目标状态),比事后 panic 更可控。

立即学习go语言免费学习笔记(深入)”;

  • 所有 State 方法只返回「下一步该做什么」,例如 func (s *IdleState) InsertCoin() (nextState State, err error)
  • 实际赋值 machine.currentState = nextState 必须在 VendingMachine 的方法内完成,并加 machine.mu.Lock()
  • 如果转移需异步(如网络请求后才切换),不要在 State 方法里启 goroutine,而是返回 channel 或 callback,由外部协调

FSM 初始化和默认状态怎么设才安全

常见错误是把初始状态写成 currentState: &IdleState{},但 IdleState 如果依赖外部资源(比如数据库连接、日志器),而初始化时这些还没准备好,就会 panic。更隐蔽的问题是:如果 IdleState 是零值结构体,而它的方法里用了未初始化的字段(比如 s.logger.Info),运行时直接 nil pointer dereference。

初始化必须确保所有状态对象的依赖都已注入。推荐用工厂函数或构造器显式传参,而不是裸字面量。

  • 不要用结构体字面量直接初始化状态,改用带参数的构造函数,如 NewIdleState(logger *zap.Logger)
  • VendingMachineNewVendingMachine 函数里完成所有状态的初始化,并校验必要字段非 nil
  • 启动时先设为 nil 状态,再调用 Reset() 方法进入初始态,避免「半初始化」状态被误用

如何避免状态泄漏和内存占用失控

有些实现会为每次状态转移 new 一个新状态对象(比如 &SoldState{}),但如果状态频繁切换(如每秒上百次),GC 压力会明显上升。更麻烦的是,如果某个状态持有了长生命周期资源(如 *sql.Txhttp.Client),又没提供 Close()Teardown() 方法,这些资源就永远卡在内存里。

状态对象应该轻量、无状态(stateless),或者明确管理生命周期。复杂资源交给 FSM 主体持有,状态只负责逻辑分支。

  • 状态结构体不要包含大字段(如 []bytemap[string]interface{}),这些数据放 VendingMachine 里共享
  • 如果状态必须持有资源(如临时文件句柄),定义 Exit() 方法,在切换前由 FSM 主动调用
  • 考虑复用状态实例(如单例模式),只要它不保存 per-transition 数据,就完全安全

状态模式真正的难点不在「怎么写接口」,而在「谁负责决策转移」和「谁持有资源生命周期」。这两点模糊了,代码很快变成一连串 if-else 的马甲。Go 的简洁性反而会放大设计偏差——没有虚函数强制约束,更容易把状态逻辑散落在各处。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

211

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

247

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

357

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

214

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

410

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

510

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

201

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

1539

2025.06.17

chatgpt使用指南
chatgpt使用指南

本专题整合了chatgpt使用教程、新手使用说明等等相关内容,阅读专题下面的文章了解更多详细内容。

0

2026.03.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 6.3万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号