github.com/expr-lang/expr 是一个 Go 语言的表达式求值库,它允许你在运行时安全地执行表达式。主要用途包括:
1.表达式求值:
go
program, err := expr.Compile("2 + 2")
if err != nil {
// 处理错误
}
result, err := expr.Run(program, nil)
// result 将是 4
2.条件表达式
go
program, err := expr.Compile("age > 18 && name == 'John'")
if err != nil {
// 处理错误
}
result, err := expr.Run(program, map[string]interface{}{
"age": 20,
"name": "John",
})
// result 将是 true
3.复杂表达式
go
program, err := expr.Compile("sum(numbers) > 100 && len(numbers) > 0")
if err != nil {
// 处理错误
}
result, err := expr.Run(program, map[string]interface{}{
"numbers": []int{1, 2, 3, 4, 5},
"sum": func(numbers []int) int {
sum := 0
for _, n := range numbers {
sum += n
}
return sum
},
})
主要特点:
安全性:表达式在沙箱环境中执行
性能:编译后的表达式执行速度快
灵活性:支持自定义函数和变量
类型安全:支持类型检查
常见用途:
规则引擎
配置验证
动态条件判断
数据过滤
业务规则执行
例如,在配置验证中:
go
type Config struct {
MaxSize int
MinSize int
}
config := Config{MaxSize: 100, MinSize: 10}
program, err := expr.Compile("MaxSize > MinSize")
if err != nil {
// 处理错误
}
result, err := expr.Run(program, config)
if err != nil {
// 处理错误
}
if !result.(bool) {
// 配置无效
}
在业务规则中:
go
type Order struct {
Amount float64
Items int
}
order := Order{Amount: 100, Items: 5}
program, err := expr.Compile("Amount > 50 && Items > 0")
if err != nil {
// 处理错误
}
result, err := expr.Run(program, order)
if err != nil {
// 处理错误
}
if result.(bool) {
// 订单有效
}
使用注意事项
expr.Compile 方法的性能和使用注意事项如下:
1.编译性能:
go
// 编译性能
program, err := expr.Compile("2 + 2")
编译时间通常很短,在微秒级别
但对于复杂表达式,编译时间会相应增加
建议缓存编译结果,避免重复编译
2.缓存编译结果:
go
// 使用 sync.Map 缓存编译结果
var compiledExpressions sync.Map
func getCompiledExpression(expr string) (*expr.Program, error) {
// 先查找缓存
if cached, ok := compiledExpressions.Load(expr); ok {
return cached.(*expr.Program), nil
}
// 编译新表达式
program, err := expr.Compile(expr)
if err != nil {
return nil, err
}
// 存入缓存
compiledExpressions.Store(expr, program)
return program, nil
}
3.错误处理:
go
// 完整的错误处理
program, err := expr.Compile("invalid expression")
if err != nil {
switch e := err.(type) {
case *expr.Error:
// 处理表达式错误
log.Printf("Expression error: %v", e)
default:
// 处理其他错误
log.Printf("Unexpected error: %v", e)
}
return
}
4.类型安全:
go
// 使用类型检查
env := map[string]interface{}{
"age": 20,
"name": "John",
}
// 编译时进行类型检查
program, err := expr.Compile("age > 18 && name == 'John'", expr.Env(env))
if err != nil {
// 处理类型错误
return
}
5.并发安全:
go
// 使用互斥锁保护缓存
var (
cache = make(map[string]*expr.Program)
cacheLock sync.RWMutex
)
func getCompiledExpression(expr string) (*expr.Program, error) {
cacheLock.RLock()
if program, ok := cache[expr]; ok {
cacheLock.RUnlock()
return program, nil
}
cacheLock.RUnlock()
cacheLock.Lock()
defer cacheLock.Unlock()
program, err := expr.Compile(expr)
if err != nil {
return nil, err
}
cache[expr] = program
return program, nil
}