golang高度可定制的表达式语言插件库gval的使用
Golang高度可定制的表达式语言插件库gval的使用
Gval (Go eVALuate) 是一个支持评估任意表达式的库,特别是类似Go语言的表达式。
基本功能
Gval可以评估带参数的表达式,支持算术、逻辑和字符串操作:
基本示例
package main
import (
"fmt"
"github.com/PaesslerAG/gval"
)
func main() {
// 基本表达式
value, err := gval.Evaluate("10 > 0", nil)
fmt.Println(value, err) // true <nil>
// 带参数的表达式
value, err = gval.Evaluate("foo > 0", map[string]interface{}{"foo": 5})
fmt.Println(value, err) // true <nil>
// 嵌套参数表达式
value, err = gval.Evaluate("foo.bar > 0", map[string]interface{}{
"foo": map[string]interface{}{"bar": 3},
})
fmt.Println(value, err) // true <nil>
// 算术表达式
value, err = gval.Evaluate("(requests_made * requests_succeeded / 100) >= 90",
map[string]interface{}{
"requests_made": 100,
"requests_succeeded": 95,
})
fmt.Println(value, err) // false <nil>
// 字符串表达式
value, err = gval.Evaluate(`http_response_body == "service is ok"`,
map[string]interface{}{"http_response_body": "service is ok"})
fmt.Println(value, err) // true <nil>
// 浮点数表达式
value, err = gval.Evaluate("(mem_used / total_mem) * 100",
map[string]interface{}{
"mem_used": 750,
"total_mem": 1000,
})
fmt.Println(value, err) // 75 <nil>
}
自定义功能
Gval可以轻松扩展自定义函数或运算符:
package main
import (
"fmt"
"github.com/PaesslerAG/gval"
"time"
)
func main() {
// 自定义日期比较函数
language := gval.Full(
gval.Function("date", func(args ...interface{}) (interface{}, error) {
if len(args) != 1 {
return nil, fmt.Errorf("date expects exactly one string argument")
}
s, ok := args[0].(string)
if !ok {
return nil, fmt.Errorf("date expects a string argument")
}
return time.Parse("2006-01-02", s)
}),
)
value, err := language.Evaluate(`date("2014-01-02") > date("2014-01-01")`, nil)
fmt.Println(value, err) // true <nil>
// 自定义字符串长度函数
language = gval.Full(
gval.Function("strlen", func(args ...interface{}) (interface{}, error) {
if len(args) != 1 {
return nil, fmt.Errorf("strlen expects exactly one string argument")
}
s, ok := args[0].(string)
if !ok {
return nil, fmt.Errorf("strlen expects a string argument")
}
return len(s), nil
}),
)
value, err = language.Evaluate(`strlen("someReallyLongInputString") <= 16`, nil)
fmt.Println(value, err) // false <nil>
}
性能优化
可以解析gval.Expression一次并多次重用:
package main
import (
"fmt"
"github.com/PaesslerAG/gval"
)
func main() {
// 解析表达式一次
expression, err := gval.Full().NewEvaluable("(requests_made * requests_succeeded / 100) >= 90")
if err != nil {
panic(err)
}
// 多次使用不同的参数评估
for i := 0; i < 5; i++ {
value, err := expression.Eval(map[string]interface{}{
"requests_made": 100,
"requests_succeeded": 90 + i,
})
fmt.Println(value, err)
}
// 输出:
// true <nil>
// true <nil>
// false <nil>
// false <nil>
// false <nil>
}
参数访问
变量可以通过字符串字面量访问:
package main
import (
"fmt"
"github.com/PaesslerAG/gval"
)
func main() {
// 点选择器访问嵌套参数
value, err := gval.Evaluate("foo.bar > 0", map[string]interface{}{
"foo": map[string]interface{}{"bar": 3},
})
fmt.Println(value, err) // true <nil>
// 方括号选择器访问数组和map
value, err = gval.Evaluate("foo[0] > 0", map[string]interface{}{
"foo": []int{1, 2, 3},
})
fmt.Println(value, err) // true <nil>
value, err = gval.Evaluate(`foo["bar"] > 0`, map[string]interface{}{
"foo": map[string]int{"bar": 3},
})
fmt.Println(value, err) // true <nil>
}
默认语言特性
gval.Full包含以下元素:
- 修饰符:
+
-
/
*
&
|
^
**
%
>>
<<
- 比较器:
>
>=
<
<=
==
!=
=~
!~
- 逻辑运算符:
||
&&
- 数字常量,作为64位浮点数(
12345.678
) - 字符串常量(双引号:
"foobar"
) - 日期函数’Date(x)’,使用RFC3339、ISO8601、ruby日期或unix日期的任何排列
- 布尔常量:
true
false
- 控制评估顺序的括号
(
)
- Json数组:
[1, 2, "foo"]
- Json对象:
{"a":1, "b":2, "c":"foo"}
- 前缀:
!
-
~
- 三元条件:
?
:
- 空值合并:
??
自定义语言
Gval是完全可定制的,每个常量、函数或运算符都可以单独定义:
package main
import (
"fmt"
"github.com/PaesslerAG/gval"
)
func main() {
// 创建自定义语言
language := gval.NewLanguage(
gval.Arithmetic(), // 包含算术运算符
gval.Text(), // 包含文本操作
gval.PropositionalLogic(), // 包含逻辑运算符
gval.Function("hello", func(args ...interface{}) (interface{}, error) {
return "Hello World!", nil
}),
)
value, err := language.Evaluate("hello() + ' How are you?'", nil)
fmt.Println(value, err) // Hello World! How are you? <nil>
}
自定义选择器
如果你想为选择器提供自定义逻辑,可以在你的结构体上实现SelectGVal(ctx context.Context, k string) (interface{}, error)
方法:
package main
import (
"context"
"fmt"
"github.com/PaesslerAG/gval"
)
type customSelector struct {
values map[string]interface{}
}
func (c customSelector) SelectGVal(ctx context.Context, k string) (interface{}, error) {
v, ok := c.values[k]
if !ok {
return nil, fmt.Errorf("unknown field %s", k)
}
return v, nil
}
func main() {
selector := customSelector{
values: map[string]interface{}{
"foo": 42,
"bar": "baz",
},
}
value, err := gval.Evaluate("foo + bar", selector)
fmt.Println(value, err) // 42baz <nil>
}
性能
该库旨在快速运行,但对于大多数应用程序来说已经足够快了。如果性能是一个问题,请确保只创建一次表达式语言,包含所有函数、常量和运算符。
更多关于golang高度可定制的表达式语言插件库gval的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang高度可定制的表达式语言插件库gval的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Gval - Go 高度可定制的表达式语言插件库
Gval 是一个强大的 Go 语言表达式求值库,它提供了高度可定制的表达式解析和求值功能。下面我将详细介绍 Gval 的主要特性和使用方法。
Gval 核心特性
- 简单易用:提供简洁的 API 接口
- 高度可扩展:支持自定义函数、运算符和变量
- 类型安全:支持类型检查和转换
- 性能优异:表达式会被预编译以提高执行效率
基本使用示例
package main
import (
"fmt"
"github.com/PaesslerAG/gval"
)
func main() {
// 最简单的表达式求值
value, err := gval.Evaluate("1 + 2", nil)
if err != nil {
panic(err)
}
fmt.Println(value) // 输出: 3
// 带变量的表达式
value, err = gval.Evaluate("a + b", map[string]interface{}{
"a": 10,
"b": 20,
})
if err != nil {
panic(err)
}
fmt.Println(value) // 输出: 30
}
自定义函数
func main() {
// 创建自定义函数
eval := gval.Full(
gval.Function("pow", func(args ...interface{}) (interface{}, error) {
if len(args) != 2 {
return nil, fmt.Errorf("pow expects exactly 2 arguments")
}
x, ok := args[0].(float64)
if !ok {
return nil, fmt.Errorf("first argument must be a number")
}
y, ok := args[1].(float64)
if !ok {
return nil, fmt.Errorf("second argument must be a number")
}
return math.Pow(x, y), nil
}),
)
value, err := eval("pow(2, 3)", nil)
if err != nil {
panic(err)
}
fmt.Println(value) // 输出: 8
}
自定义运算符
func main() {
// 创建自定义运算符
eval := gval.Full(
gval.InfixOperator("**", func(a, b interface{}) (interface{}, error) {
x, ok := a.(float64)
if !ok {
return nil, fmt.Errorf("first operand must be a number")
}
y, ok := b.(float64)
if !ok {
return nil, fmt.Errorf("second operand must be a number")
}
return math.Pow(x, y), nil
}),
)
value, err := eval("2 ** 3", nil)
if err != nil {
panic(err)
}
fmt.Println(value) // 输出: 8
}
复杂表达式示例
func main() {
// 复杂表达式示例
eval := gval.Full()
params := map[string]interface{}{
"user": map[string]interface{}{
"name": "Alice",
"age": 30,
"roles": []string{"admin", "editor"},
},
"settings": map[string]interface{}{
"max_login_attempts": 5,
"block_duration": "30m",
},
}
expression := `
user.age >= 18 &&
contains(user.roles, "admin") &&
settings.max_login_attempts > 3
`
value, err := eval(expression, params)
if err != nil {
panic(err)
}
fmt.Println(value) // 输出: true
}
性能优化 - 预编译表达式
func main() {
// 预编译表达式以提高性能
expression := "a * b + c / d"
// 编译阶段
evaluable, err := gval.Full().NewEvaluable(expression)
if err != nil {
panic(err)
}
// 执行阶段 (可重复使用)
for i := 0; i < 5; i++ {
value, err := evaluable(map[string]interface{}{
"a": 10 + i,
"b": 20 + i,
"c": 30 + i,
"d": 2,
})
if err != nil {
panic(err)
}
fmt.Println(value)
}
}
实际应用场景
- 规则引擎:业务规则配置化
- 动态配置:根据条件动态计算配置值
- 权限控制:复杂的权限判断逻辑
- 数据过滤:动态数据过滤条件
总结
Gval 是一个功能强大且灵活的 Go 表达式求值库,通过其丰富的扩展接口,可以轻松实现各种复杂的表达式逻辑。它的主要优势在于:
- 简洁直观的 API 设计
- 强大的扩展能力(函数、运算符等)
- 良好的性能(支持预编译)
- 丰富的内置功能(类型转换、集合操作等)
对于需要动态表达式求值的 Go 项目,Gval 是一个非常值得考虑的选择。