这是关于在 Rust 中使用 CGP 编程可扩展数据类型的系列文章的第二部分,主要内容如下:
- 系列概述:包括模块化应用构建和可扩展构建器(第一部分)、模块化解释器和可扩展访问者(本部分)、实现可扩展记录(第三部分)、实现可扩展变体(第四部分)。
- 扩展访问者模式:Rust 中的访问者模式常用于遍历抽象语法树或序列化有效负载,传统访问者模式存在固有缺陷,如扩展性受限,而 CGP 的可扩展访问者模式旨在解决这些问题,保持类型安全和可扩展性。
- 表达式问题:以实现玩具算术语言的解释器为例,说明传统表达式定义方式存在的问题,如随着语言的发展,修改表达式枚举会导致所有相关函数的模式匹配代码都需要更新,导致紧密耦合,CGP 的可扩展访问者模式可解决此问题。
- 评估计算机:通过定义独立的
Plus
结构体和Computer
特质,实现了可扩展且解耦的评估逻辑,不同的算术运算(如加法、乘法、常量)都有各自的提供者,通过递归调用计算子表达式,最终得到结果。 - 评估具体表达式:定义具体的表达式类型
MathExpr
,并通过#[cgp_context]
声明定义解释器上下文Interpreter
,使用delegate_components!
宏进行组件调度,实现了从具体表达式到数值结果的评估。 - 调度评估:通过
DispatchEval
提供者和MatchWithValueHandlers
访问器调度器,实现了对MathExpr
枚举的评估,避免了在 Rust 特质解析系统中的循环依赖问题,提供了干净、声明式且可扩展的方式来评估复杂的枚举。 - 转换为 Lisp 表达式:将算术表达式转换为 Lisp 表达式,介绍了
LispExpr
枚举的定义和结构,通过ComputerRef
特质和MatchWithValueHandlersRef
访问器调度器,实现了从MathExpr
到LispExpr
的转换,展示了 CGP 的模块化和可扩展性。 - 构建带有子枚举的变体:定义
LispSubExpr
枚举,用于表示 Lisp 表达式的子集,通过CanUpcast
特质实现从LispSubExpr
到LispExpr
的安全类型转换,展示了 CGP 的向上转换机制在构建枚举值时的灵活性。 高级技术:
- 二进制运算符提供程序:通过提取共享结构,实现了通用的
BinaryOpToLisp
提供者,用于处理加法和乘法表达式,减少了代码重复,提高了代码的可维护性和可扩展性。 - 基于代码的调度:利用
Code
参数在ComputerRef
特质中构建类型级 DSL,实现了基于计算意图(评估或转换)的代码调度,通过delegate_components!
宏实现了灵活的组件组合,展示了 CGP 的分层调度模型的优势。
- 二进制运算符提供程序:通过提取共享结构,实现了通用的
- 扩展
MathExpr
:通过定义新的MathPlusExpr
表达式类型,展示了 CGP 在支持语言扩展方面的模块化和灵活性,包括添加减法和取反操作,无需修改现有代码,提供者可以无缝工作。 - 结论:可扩展变体和 CGP 访问者模式在模块化解释器设计中开辟了新领域,能够以可重用、解耦的组件进行表达式评估和转换,保持类型安全,无需在可扩展性和类型安全之间进行权衡。第三部分将深入探讨可扩展记录的底层实现细节。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。