Go标准库无eval,用go/parser+go/constant可安全求值纯数字四则表达式,但不支持变量、函数或逻辑运算;需前置校验输入合法性,支持变量时应改用antonmedv/expr等专用引擎。
Go 语言标准库没有内置表达式求值器,eval 类功能需手动实现或借助第三方包;直接用 go/parser + go/constant 可安全解析简单算术表达式,但不支持变量、函数调用或逻辑运算。
go/parser 和 go/constant 解析并计算纯数字表达式这是最轻量、最安全的方案,适用于形如 "2 + 3 * 4" 或 "(10 - 2) / 2" 的整数/浮点数四则运算。它绕过字符串拼接执行,避免代码注入风险。
"const _ = "
go/parser.ParseExpr 解析 AST,再用 go/constant.Int64Val 或 Float64Val 提取结果"6.0 / 4")package mainimport ( "fmt" "go/ast" "go/parser" "go/token" "go/constant" )
func evalExpr(s string) (float64, error) { expr, err := parser.ParseExpr("const _ = " + s) if err != nil { return 0, err }
// 确保是二元运算或字面量 tv, err := ast.EvalExpr(token.NewFileSet(), nil, expr) if err != nil { return 0, err } switch tv.Kind() { case constant.Int: return constant.Int64Val(tv.Value), nil case constant.Float: return constant.Float64Val(tv.Value), nil default: return 0, fmt.Errorf("unsupported constant kind: %v", tv.Kind()) }}
func main() { result, _ := evalExpr("2 + 3 * 4") fmt.Println(result) // 14 }
遇到
invalid operation或undefined: xxx错误怎么办这类错误几乎都源于输入不是合法 Go 常量表达式:
undefined: x → 表达式里写了变量名(如 "x + 1"),而 go/parser 不做变量绑定invalid operation: operator + not defined on string → 输入含未加引号的字符串字面量(如 "hello + world"),应只传数字和运算符syntax error: unexpected newline → 字符串含换行或注释,需
提前清理(strings.TrimSpace + 去掉 // 和 /* */)ParseExpr 直接返回语法错误,建议前置校验 len(strings.TrimSpace(s)) == 0
go/parser,换用 antonmedv/expr
go/parser 天然不支持运行时变量代入,强行在 AST 上做符号表替换极易出错且破坏类型安全。更现实的做法是引入轻量表达式引擎:
github.com/antonmedv/expr 支持变量、布尔逻辑、比较、基础函数(len, round),语法接近 Go 但更宽松exec、无反射调用),安全性可控go/parser 略低,但对千次/秒以下的计算场景无感user.Name),需显式启用 expr.Env 并传入允许的字段名列表import (
"fmt"
"github.com/antonmedv/expr"
)
func main() {
env := map[string]interface{}{"a": 5, "b": 3}
code := "a * b + 2"
program, := expr.Compile(code)
output, := expr.Run(program, env)
fmt.Println(output) // 17
}
真正麻烦的不是写个计算器,而是决定「哪些东西必须禁止」:用户输入是否可能含恶意构造(如超深递归、超长数字、科学计数法溢出)?是否要限制执行时间?这些边界问题比语法解析本身更消耗精力。