开发者

Go表达式引擎expr基础用法实战指南

目录
  • 玩转 Go 表达式引擎:expr 实战指南
    • 什么是 expr?
    • 快速入门:第一个 expr 程序
    • 访问数据:从简单到复杂
      • 1. 访问结构体字段
      • 2. 访问 Map 键值
      • 3. 访问嵌套结构
      • 4. 处理切片和数组
    • 高级特性:让表达式更强大
      • 1. 空安全访问
      • 2. 自定义函数
      • 3. 编译优化
    • 结合模板引擎:动态渲染内容
      • 总结

      玩转 Go 表达式引擎:expr 实战指南

      在日常开发中,我们经常需要处理动态表达式计算、业务规则判断等场景。Go 标准库虽然提供了模板引擎的条件判断,但面对复杂逻辑时显得力不从心。今天要介绍的 expr 库,正是为解决这类问题而生的轻量级表达式引擎。

      什么是 expr?

      expr 是一个高性能的 Go 表达式引擎,它允许你在代码中安全地执行动态生成的表达式。其语法接近 Go 语言,支持变量访问、函数调用、逻辑运算等,非常适合以下场景:

      • 动态业务规则判断
      • 配置化条件过滤
      • 模板中的动态计算
      • 复杂逻辑的动态执行

      快速入门:第一个 expr 程序

      先从最简单的表达式计算开始,比如计算 1+10 的结果:

      package main
      import (
      	"fmt"
      	"github.com/expr-lang/expr"
      )
      func main() {
      	// 定义表达式
      	code := "1 + 10"
      	// 直接执行表达式(无需环境变量)
      	result, err := expr.Eval(code, nil)
      	if err != nil {
      		panic(err)
      	}
      	fmt.Prinpythontln(result) // 输出:11
      }

      这段代码展示了 expr 的核心用法:通过 expr.Eval() 函数直接执行表达式字符串,第一个参数是表达式,第二个参数是执行环境(可以是结构体、map 等)。

      访问数据:从简单到复杂

      expr 最强大的功能之一是能够访问外部数据,支持多种数据类型和嵌套结构。

      1. 访问结构体字段

      type User struct {
      	Name string
      	Age  int
      }
      func main() {
      	user := User{Name: "Alice", Age: 25}
      	// 表达式访问结构体字段
      	code := `Name == "Alice" && Age > 18`
      	result, _ := expr.Eval(code, user)
      	fmt.Println(result) // 输出:true
      }

      注意:结构体字段必须首字母大写(导出字段),否则 expr 无法访问(受 Go 反射机制限制)。

      2. 访问 Map 键值

      func main() {
      	data := map[string]interface{}{
      		"product": "phone",
      		"price":   3999,
      	}
      	// 两种访问方式等价
      	code := `product == "phone" && .price > 3000`
      	result, _ := expr.Eval(code, data)
      	fmt.Println(result) // 输出:true
      }

      3. 访问嵌套结构

      对于嵌套的结构体或 Map,使用 . 符号链式访问:

      func main() {
      	data := map[string]interface{}{
      		"user": map[string]interface{}{
      			"name": "Bob",
      			"address": map[string]interface{}{
      				"city": "Beijing",
      			},
      		},
      	}
      	// 访问嵌套 Map 的属性
      	code := `user.name == "Bobhttp://www.devze.com" && user.address.city == "Beijing"`
      	result, _ := expr.Eval(code, data)
      	fmt.Println(result) // 输出:true
      }

      4. 处理切片和数组

      结合 len() 函数可以方便地处理切片:

      func main() {
      	data := map[string]interface{}{
      		"tags": []string{"go", "expr", "template"},
      	}
      	// 判断切片长度并访问元素
      	code := `len(tags) == 3 && tags[0] == "go"`
      	result, _ := expr.Eval(code, data)
      	fmt.Println(result) // 输出:true
      }

      高级特性:让表达式更强大

      1. 空安全访问

      当访问可能为 nil 的字段时,使用 ?. 避免 panic:

      code := `user?.address?.city == "Shanghai"`
      // 如果 user 或 address 为 nil,表达式返回 false 而非错误
      

      2. 自定义函数

      expr 支持注册自定义函数,扩展表达式能力:

      func majsin() {
      	// 定义自定义函数:计算平方
      	square := func(x int) int {
      		return x * x
      	}
      	// 注册函数并执行表达式
      	env := map[string]interface{}{
      		"square": square,
      		"num":    5,
      	}
      	code := `square(num) == 25`
      	result, _ := expr.Eval(code, env)
      	fmt.Println(result) // 输出:true
      }

      3. 编译优化

      对于需要多次执行的表达式,先编译再执行可以提升性能:

      func main() {
      	code := `a + b * c`
      	data := map[string]int{"a": 1, "b": 2, "c": 3}
      	// 编译表达式
      	program, _ := expr.Compile(code, expr.Env(data))
      	// 多次执行(适合循环场景)
      	for i := 0; i < 3; i++ {
      		result, _ := expr.Run(program, data)
      		fmt.Println(result) // 均输出:7
      	}
      }

      结合模板引擎:动态渲染内容

      虽然 expr 不是模板引擎,但可以与 Go 标准模板配合,实现动态内容渲染:

      package main
      import (
      python	"os"
      	"text/template"
      	"github.com/expr-lang/expr"
      )
      func main() {
      	// 定义包含表达式的模板
      	tplContent := `
      	计算结果:{{calc "a + b * 2"}}
      	判断结果:{{if calc "a > 10"}}a 大于 10{{else}}a 不大于 10{{end}}
      	`
      	// 准备数据
      	data := map[string]int{"a": 5, "b": 3}
      	// 创建模板并注册 calc 函数
      	tpl := template.New("test").Funcs(template.FuncMap{
      		"calc": func(exprCode string) (interface{}, error) {
      			return expr.Eval(exprCode, data)
      		},
      	})
      	// 解析并执行模板
      	tpl.Parse(tplContent)
      	tpl.Execute(os.Stdout, nil)
      }

      输出结果:

          计算结果:11

          判断结果:a 不大于 10

      总结

      expr 作为一款轻量级表达式引擎,以其接近 Go 的语法、良好的性能和丰富的特性,成为处理动态表达式场景的理想选择。无论是简单的数值计算,还是复杂的业务规则判断,expr 都能胜任。

      通过本文介绍的基础用法和高级特性,相信你已经掌握了 expr 的核心能力。在实际项目中,还可以结合配置文件、数据库存储等方式,实现更灵活的动态规则系统。

      如果你需要处理复杂的业务规则php引擎场景,expr 绝对值得一试!

      到此这篇关于Go表达式引擎expr基础用法实战指南的文章就介绍到这了,更多相关go表达式引擎expr 内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

      0

      上一篇:

      下一篇:没有了

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜