当前位置: 首页 > news >正文

学习笔记十六——Rust Monad从头学

🧠 零基础也能懂的 Rust Monad:逐步拆解 + 三大定律通俗讲解 + 实战技巧


📣 第一部分:Monad 是什么?

Monad 是一种“包值 + 链操作 + 保持结构”的代码模式,用来处理带上下文的值,并方便连续处理。

✅ 用人话怎么说?

你可以把 Monad 想成“装了值的容器”,它还带了一套通用的处理流程,能帮你做以下三件事:

  1. 包裹值:比如用户输入 5,你包装成 Some(5),表示“有值”。
  2. 自动判断是否处理:值存在就处理,不存在就跳过。
  3. 统一结构,不出错:你不管怎么处理,最后结构还保持不变(比如一直是 Option<T>)。

🧩 第二部分:Monad 三大组成要素

这三样东西是判断一个类型是不是 Monad 的“标准配件”。

要素名称用通俗话解释Rust 中的样子
① 包装器类型构造器把值“装进盒子”Some(x)Ok(x)async { x }
② 起点函数单位函数(unit)把普通值变成最简单的 Monad 容器Some(x)Ok(x)
③ 链接器绑定函数(bind)如果有值就继续调用下一个操作.and_then(...)

这些特性让我们可以放心大胆地“串”代码逻辑。


🔍 第三部分:什么叫“上下文”和“结构保持不变”?

例子上下文的含义
Option<T>这个值可能为空(None)
Result<T,E>这个操作可能失败
Future<T>这个值未来才会得到

✅ 举个例子:

Some(5).and_then(|x| Some(x + 1)).and_then(|y| Some(y * 2))

这里的每一步都保留了 Option 结构,不会突然变成裸值 i32。这就叫结构不变


🧪 第四部分:三大定律彻底通俗讲清楚!

✅ 左单位律(Left Identity)

定义:

unit(x).bind(f) == f(x)

用人话说:

把值放进盒子再处理,和你直接处理这个值,没区别!

示例:

fn f(x: i32) -> Option<i32> {Some(x + 1)
}let a = Some(5).and_then(f); // 左边:unit(x).bind(f)
let b = f(5);                // 右边:直接调用 f(x)assert_eq!(a, b);            // 都是 Some(6)

口诀:“左边装进去再处理,和直接处理一样。”


✅ 右单位律(Right Identity)

定义:

m.bind(unit) == m

用人话说:

如果你对值“啥也不干就原样放回去”,等于什么都没做。

示例:

let x = Some("hi");
let result = x.and_then(|v| Some(v)); // 就是 unit(v)assert_eq!(result, x); // 不变

口诀:“右边原样返回,啥也没改变。”


✅ 结合律(Associativity)

定义:

m.bind(f).bind(g) == m.bind(|x| f(x).bind(g))

用人话说:

不管你是“先 f 后 g”还是“把 f 和 g 合起来一起处理”,结果一样!

示例:

fn f(x: i32) -> Option<i32> { Some(x + 1) }
fn g(x: i32) -> Option<i32> { Some(x * 2) }let m = Some(3);
let a = m.and_then(f).and_then(g);
let b = m.and_then(|x| f(x).and_then(g));assert_eq!(a, b); // 都是 Some(8)

理解要点:

  • f(x) 是第一步
  • g(...) 是第二步
  • 两种写法是“逐步绑定”和“整体组合”的区别

口诀:“多步绑定能拆合,合成一起也不差。”


📘 第五部分:从例子理解 Option 是怎么应用 Monad 的

fn validate_email(email: Option<String>) -> Option<String> {email.and_then(|e| {if e.contains("@") {Some(e)} else {None}})
}

每行拆解:

  • Option<String>:这个邮箱可能存在也可能不存在
  • .and_then(...):如果有值就执行闭包,否则直接 None
  • |e| {...}:取出值 e 后判断是否含有 @
  • 满足条件返回 Some(e),否则返回 None

体现了什么?

  • ✅ 用 Some(email) 开始:unit(x)
  • ✅ 用 .and_then(...) 处理:bind
  • ✅ 最后返回的仍是 Option<String>:结构不变

🔧 第六部分:.map() vs .and_then() 有啥区别?

方法用法说明示例
.map()对值做处理,结果仍在容器内`Some(2).map(
.and_then()处理后返回另一个容器(嵌套)`Some(2).and_then(

.map() 相当于你“只动里面的值”,.and_then() 是你“根据值决定接下去是否继续”。


🔁 第七部分:组合多个操作 - 用 Monad 串业务逻辑

fn parse_id(s: &str) -> Option<i32> {s.parse().ok()
}fn check_id(id: i32) -> Option<i32> {if id > 0 { Some(id) } else { None }
}fn query_user(id: i32) -> Option<String> {Some(format!("用户{}", id))
}let user = Some("42").and_then(parse_id).and_then(check_id).and_then(query_user);

用人话解释:

如果字符串能成功转成数字、这个数字大于 0、还能找到用户,就返回用户名;否则中途停止。

这就是典型的:组合多个失败可能的操作


🧾 第八部分:总结表格

类型类型构造器unit函数bind函数上下文解释
OptionSome(x)Some(x)and_then可能没有值
ResultOk(x)/Err(e)Ok(x)and_then成功/失败状态
Futureasync { x }asyncawait / then值尚未获得

✅ 结语

掌握 Monad 不是为了炫技,而是为了安全、优雅、高复用地处理流程和异常

如果你能理解这三句话:

  • 我可以从值开始(左单位律)
  • 我可以随时停下不处理(右单位律)
  • 我可以拆写也能合写(结合律)

相关文章:

  • 过拟合和欠拟合
  • windows:右键jpg等格式文件后文件管理器卡住/崩溃
  • Sysstat学习
  • 2025年CNG 汽车加气站操作工考试真题练习
  • OpenAI全新旗舰款模型GPT4.1系列
  • 大模型——Crawl4AI基于会话的爬虫技术
  • satoken的奇奇怪怪的错误
  • 使用DPlayer和HLS前端封装视频播放
  • 二叉查找树和B树
  • VC++中/GS防止缓冲区溢出指南
  • 亚瑟阿伦36问
  • 鬼泣:远程攻击
  • 《AI大模型应知应会100篇》第23篇:角色扮演技巧:让AI成为你需要的专家
  • QML 信号与槽
  • Python学习笔记0
  • 在昇腾环境中编译TEI报错及解决
  • 二叉平衡搜索树:AVL树
  • 【前端vue生成二维码和条形码——MQ】
  • TMS320F28P550SJ9学习笔记17:Lin通信SCI模式完整的收发配置
  • 【实测案例】分布式光纤嵌入U型复材无损强度检测
  • 陈文清:推进扫黑除恶常态化走深走实,有力回应人民群众对安居乐业的新期待
  • 农行一季度净利润719亿元增2.2%,不良率微降至1.28%
  • 西夏文残碑等文物来沪,见证一段神秘灿烂的历史
  • 83岁连丽如每周登台说书,还上了15堂连派评书课
  • 五一假期如何躺赚利息?来看国债逆回购操作攻略
  • 商务部新闻发言人就波音公司飞回拟交付飞机答记者问