Go用Interpreter模式实现表达式解释器:先Lexer将字符串转为Token流,再Parser按优先级递归下降构建AST,最后通过Expr接口的Eval方法递归求值,支持扩展运算符且无需修改现有逻辑。

用 Go 实现解释器模式解析表达式,核心是把字符串形式的算术表达式(如 "3 + 5 * 2")拆解成树结构,再递归求值。不依赖第三方 parser,纯手工构建词法分析(Lexer)+ 语法分析(Parser),符合 Interpreter Pattern 的经典四要素:抽象表达式、终结符、非终结符、上下文。
词法分析:把输入切分成 Token
先定义基础 Token 类型:
type TokenType string
const (
TOKEN_NUMBER TokenType = "NUMBER"
TOKEN_PLUS = "PLUS"
TOKEN_STAR = "STAR"
TOKEN_LPAREN = "LPAREN"
TOKEN_RPAREN = "RPAREN"
)
type Token struct { Type TokenType; Value string }
Lexer 遍历字符串,跳过空格,识别数字(支持多位)、运算符和括号。关键点:
立即学习“go语言免费学习笔记(深入)”;
- 数字要连续读取直到非数字字符
- 区分
-是减号还是负号——简单场景可暂不支持负数,或结合 Parser 处理 - 返回
[]Token,末尾加一个TOKEN_EOF方便 Parser 终止
语法分析:构造抽象语法树(AST)
按优先级自顶向下递归下降(Recursive Descent)。推荐实现三个层级函数:
-
ParseExpression():处理
+和-(最低优先级),调用 ParseTerm -
ParseTerm():处理
*和/(中等优先级),调用 ParseFactor -
ParseFactor():处理数字、括号(最高优先级),遇到
(就递归调用 ParseExpression
每个函数返回一个实现了 Expr 接口的 AST 节点。例如:
type Expr interface { Eval() int }
type NumberExpr struct { Value int }
func (n NumberExpr) Eval() int { return n.Value }
type BinaryExpr struct { Left, Right Expr; Op string }
func (b BinaryExpr) Eval() int {
switch b.Op {
case "+": return b.Left.Eval() + b.Right.Eval()
case "*": return b.Left.Eval() * b.Right.Eval()
default: panic("unknown op")
}
}
解释执行:调用 Eval() 递归求值
AST 构建完成后,只需对根节点调用 .Eval()。所有运算逻辑封装在各 Expr 实现里,完全符合 Interpreter Pattern 的“让语言的语法结构由多个类分别表示,每个类负责解释对应部分”的思想。
- 无需 switch 判断节点类型,靠接口多态自动分发
- 扩展新运算符(如
-、/)只需新增 Expr 实现,不修改现有逻辑 - 若需变量支持,可在
Eval()方法中传入 map[string]int 环境参数
完整流程串起来
入口函数示例:
func Evaluate(input string) int {
tokens := Lexer(input)
parser := &Parser{Tokens: tokens, Pos: 0}
expr := parser.ParseExpression()
return expr.Eval()
}
注意 Parser 中维护当前 token 下标 Pos,每次 consume 后递增;遇到错误(如括号不匹配、意外 token)应 panic 或返回 error。
基本上就这些。Go 的接口和结构体组合让 Interpreter Pattern 写起来干净利落,没有冗余抽象,也不用反射或代码生成。重点是把 Token 流稳稳转成树,剩下的就是自然的递归计算。










