go的工具库:github.com/expr-lang/expr

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
}
相关推荐
CoderCodingNo34 分钟前
【GESP】C++五级考试大纲知识点梳理, (5) 算法复杂度估算(多项式、对数)
开发语言·c++·算法
ftpeak1 小时前
JavaScript性能优化实战
开发语言·javascript·性能优化
一个很帅的帅哥2 小时前
JavaScript事件循环
开发语言·前端·javascript
驰羽2 小时前
[GO]gin框架:ShouldBindJSON与其他常见绑定方法
开发语言·golang·gin
程序员大雄学编程2 小时前
「用Python来学微积分」5. 曲线的极坐标方程
开发语言·python·微积分
云雾J视界2 小时前
开源协作2.0:GitHub Discussions+AI重构开发者社区的知识共创生态
人工智能·开源·github·discussions·知识共创·社区知识·ai重构
Jose_lz3 小时前
C#开发学习杂笔(更新中)
开发语言·学习·c#
老程序员刘飞3 小时前
项目上传到GitHub流程
github
一位代码3 小时前
python | requests爬虫如何正确获取网页编码?
开发语言·爬虫·python
看到我,请让我去学习3 小时前
Qt 控件 QSS 样式大全(通用属性篇)
开发语言·c++·qt