golang高性能表达式求值引擎插件expr的使用
Golang高性能表达式求值引擎插件Expr的使用
Expr是一个Go语言为中心设计的表达式语言,旨在提供动态配置功能,具有无与伦比的准确性、安全性和速度。
主要特性
- 内存安全:设计注重安全性,确保程序不会访问无关内存或引入内存漏洞
- 无副作用:表达式评估只计算输入输出,确保不会产生副作用
- 静态类型:确保类型正确性,防止运行时类型错误
- 高性能:采用优化编译器和字节码虚拟机
- 丰富的内置函数:提供all、none、any、one、filter和map等函数
安装
go get github.com/expr-lang/expr
使用示例
基础示例
package main
import (
"fmt"
"github.com/expr-lang/expr"
)
func main() {
env := map[string]interface{}{
"greet": "Hello, %v!",
"names": []string{"world", "you"},
"sprintf": fmt.Sprintf,
}
code := `sprintf(greet, names[0])`
program, err := expr.Compile(code, expr.Env(env))
if err != nil {
panic(err)
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println(output) // 输出: Hello, world!
}
结构体示例
package main
import (
"fmt"
"github.com/expr-lang/expr"
)
type Tweet struct {
Len int
}
type Env struct {
Tweets []Tweet
}
func main() {
code := `all(Tweets, {.Len <= 240})`
program, err := expr.Compile(code, expr.Env(Env{}))
if err != nil {
panic(err)
}
env := Env{
Tweets: []Tweet{{42}, {98}, {69}},
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println(output) // 输出: true
}
表达式示例
Expr支持多种表达式语法:
// 只允许管理员和版主审核评论
user.Group in ["admin", "moderator"] || user.Id == comment.UserId
// 判断请求是否在允许的时间窗口内
request.Time - resource.Age < duration("24h")
// 确保所有推文不超过240个字符
all(tweets, len(.Content) <= 240)
类型检查
Expr会在编译时进行类型检查:
out, err := expr.Compile(`name + age`)
// err: invalid operation + (mismatched types string and int)
// | name + age
// | .....^
使用场景
Expr适用于各种需要动态表达式求值的场景,如:
- 业务规则引擎
- 动态配置
- 条件过滤
- 权限控制
- 数据验证
Expr已被Google、Uber、GoDaddy等公司用于生产环境。
更多关于golang高性能表达式求值引擎插件expr的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang高性能表达式求值引擎插件expr的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Go高性能表达式求值引擎:expr
expr 是一个高性能的表达式求值引擎,专为 Go 语言设计。它提供了简单易用的 API 来解析和求值表达式,支持自定义函数和变量,非常适合配置化业务逻辑、规则引擎等场景。
主要特性
- 高性能:expr 经过优化,执行速度快
- 类型安全:编译时检查表达式类型
- 简单易用:直观的 API 设计
- 可扩展:支持自定义函数和变量
- 安全:默认限制潜在危险操作
基本使用
安装
go get github.com/antonmedv/expr
简单示例
package main
import (
"fmt"
"github.com/antonmedv/expr"
)
func main() {
// 最简单的表达式求值
result, err := expr.Eval("1 + 2", nil)
if err != nil {
panic(err)
}
fmt.Println(result) // 输出: 3
// 使用环境变量
env := map[string]interface{}{
"name": "Alice",
"age": 25,
"adult": true,
"prices": []float64{10.5, 20.3, 30.1},
}
// 带变量的表达式
code := `name + " is " + age + " years old"`
result, err = expr.Eval(code, env)
if err != nil {
panic(err)
}
fmt.Println(result) // 输出: Alice is 25 years old
// 条件表达式
code = `age >= 18 && adult ? "Adult" : "Minor"`
result, err = expr.Eval(code, env)
if err != nil {
panic(err)
}
fmt.Println(result) // 输出: Adult
// 数组操作
code = `sum(prices)`
result, err = expr.Eval(code, env)
if err != nil {
panic(err)
}
fmt.Println(result) // 输出: 60.9
}
高级用法
预编译表达式
对于需要多次执行的表达式,可以先编译再执行以提高性能:
program, err := expr.Compile(`price > 100 && in_stock`, expr.Env(map[string]interface{}{
"price": 0,
"in_stock": false,
}))
if err != nil {
panic(err)
}
// 多次执行
for _, product := range products {
result, err := expr.Run(program, map[string]interface{}{
"price": product.Price,
"in_stock": product.InStock,
})
if err != nil {
panic(err)
}
if result.(bool) {
fmt.Println("High value product:", product.Name)
}
}
自定义函数
env := map[string]interface{}{
"greet": func(name string) string {
return "Hello, " + name + "!"
},
"names": []string{"Alice", "Bob", "Charlie"},
}
code := `map(names, greet)`
result, err := expr.Eval(code, env)
if err != nil {
panic(err)
}
fmt.Println(result)
// 输出: [Hello, Alice!, Hello, Bob!, Hello, Charlie!]
结构体环境
expr 也支持使用结构体作为环境:
type Env struct {
User struct {
Name string
Age int
}
Discount float64
}
program, err := expr.Compile(
`User.Age >= 18 && Discount > 0.1`,
expr.Env(Env{}),
)
if err != nil {
panic(err)
}
env := Env{
User: struct {
Name string
Age int
}{
Name: "Alice",
Age: 25,
},
Discount: 0.15,
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println(output) // 输出: true
性能优化技巧
- 预编译表达式:对于重复执行的表达式,先编译再执行
- 重用环境对象:避免频繁创建环境对象
- 限制表达式复杂度:对于不可信输入,限制表达式复杂度
- 使用简单类型:基本类型比复杂类型处理更快
安全注意事项
expr 默认是安全的,但如果你需要执行不可信输入,可以添加限制:
program, err := expr.Compile(input, expr.Env(env), expr.AllowUndefinedVariables())
expr 提供了多种选项来控制允许的操作:
AllowUndefinedVariables()
- 允许未定义变量AllowUndefinedFunctions()
- 允许未定义函数AllowBuiltins()
- 允许内置函数AllowAll()
- 允许所有操作(不推荐)
表达式语法
expr 支持丰富的表达式语法:
- 算术运算:
+
,-
,*
,/
,%
,**
- 比较运算:
==
,!=
,<
,<=
,>
,>=
- 逻辑运算:
&&
,||
,!
- 条件表达式:
a ? b : c
- 数组操作:
filter
,map
,reduce
,all
,any
,none
,one
- 字符串操作:
contains
,startsWith
,endsWith
,matches
- 其他:
in
,..
(范围),[]
(索引)
实际应用场景
- 业务规则引擎:将业务规则配置为表达式
- 数据过滤:动态过滤数据集
- 计算字段:动态计算字段值
- 条件触发:根据条件触发不同操作
- 配置化逻辑:将业务逻辑配置化而非硬编码
expr 是一个强大而灵活的工具,可以帮助你将业务逻辑从代码中解耦出来,实现更高程度的配置化和灵活性。