文档:https://godoc.org/github.com/Knetic/govaluate
参考:https://zhuanlan.zhihu.com/p/122561534
ps:casbin用到该库
govaluate与 JavaScript 中的eval功能类似,用于计算任意表达式的值。此类函数在JavaScript/Python 等动态语言中比较常见。govaluate让 Go 这个编译型语言也有了这个能力!
type EvaluableExpression
EvaluableExpression表示一组表达式标记,它们合在一起是一个可以被计算为单个值的表达式
type EvaluableExpression struct {QueryDateFormat stringChecksTypes bool}
func NewEvaluableExpression(expression string) (*EvaluableExpression, error)
- 从给定的[表达式]字符串中解析一个新的EvaluableExpression
- 如果给定表达式具有无效语法,则返回错误
func NewEvaluableExpressionWithFunctions(expression string, functions map[string]ExpressionFunction) (*EvaluableExpression, error)
- 类似于[NewEvaluableExpression],除了允许使用用户定义的函数。传入该函数的函数将对表达式可用
func (this EvaluableExpression) Eval(parameters Parameters) (interface{}, error)
- 使用给定的[参数]运行整个表达式
func (this EvaluableExpression) Evaluate(parameters map[string]interface{}) (interface{}, error)
- 与“Eval”相同,但会自动将参数映射包装到“govalute”中
type ExpressionFunction
表示可以从表达式中调用的函数。如果由于任何原因,该方法不能准确地生成一个明确的结果,则必须返回一个错误。返回的错误将停止表达式的执行。
type ExpressionFunction func(arguments ...interface{}) (interface{}, error)
type Parameters
当表达式试图使用参数时,可EvaluableExpression使用参数集合来检索参数
type Parameters interface {Get(name string) (interface{}, error)}
例子
简单表达式
func main() {expr, err := govaluate.NewEvaluableExpression("10 > 0")if err != nil {log.Fatal("syntax error:", err)}result, err := expr.Evaluate(nil)if err != nil {log.Fatal("evaluate error:", err)}fmt.Println(result) // true}
带参数表达式
func main() {expr, _ := govaluate.NewEvaluableExpression("foo > 0")parameters := make(map[string]interface{})parameters["foo"] = -1result, _ := expr.Evaluate(parameters)fmt.Println(result) // falseexpr, _ = govaluate.NewEvaluableExpression("(requests_made * requests_succeeded / 100) >= 90")parameters = make(map[string]interface{})parameters["requests_made"] = 100parameters["requests_succeeded"] = 80result, _ = expr.Evaluate(parameters)fmt.Println(result) // falseexpr, _ = govaluate.NewEvaluableExpression("(mem_used - total_mem) * 100")parameters = make(map[string]interface{})parameters["total_mem"] = 1024parameters["mem_used"] = 512result, _ = expr.Evaluate(parameters)fmt.Println(result) // -51200}
命名规范
使用govaluate与直接编写 Go 代码不同,在 Go 代码中标识符中不能出现-、+、$等符号。govaluate可以通过转义使用这些符号。有两种转义方式:
- 将名称用
[和]包裹起来,例如[response-time]; 使用
\将紧接着下一个的字符转义。func main() {expr, _ := govaluate.NewEvaluableExpression("[response-time] < 100")parameters := make(map[string]interface{})parameters["response-time"] = 80result, _ := expr.Evaluate(parameters)fmt.Println(result) // trueexpr, _ = govaluate.NewEvaluableExpression("response\\-time < 50")parameters = make(map[string]interface{})parameters["response-time"] = 80result, _ = expr.Evaluate(parameters)fmt.Println(result) // false}
一次”编译”多次运行
func main() {expr, _ := govaluate.NewEvaluableExpression("a + b")parameters := make(map[string]interface{})parameters["a"] = 1parameters["b"] = 2result, _ := expr.Evaluate(parameters)fmt.Println(result) // 3parameters = make(map[string]interface{})parameters["a"] = 10parameters["b"] = 20result, _ = expr.Evaluate(parameters)fmt.Println(result) // 30}
函数
如果仅仅能进行常规的算数和逻辑运算,
govaluate的功能会大打折扣。govaluate提供了自定义函数的功能。所有自定义函数需要先定义好,存入一个map[string]govaluate.ExpressionFunction变量中,然后调用govaluate.NewEvaluableExpressionWithFunctions()生成表达式,此表达式中就可以使用这些函数了。自定义函数类型为func (args ...interface{}) (interface{}, error),如果函数返回错误,则这个表达式求值返回错误。func main() {functions := map[string]govaluate.ExpressionFunction{"strlen": func(args ...interface{}) (interface{}, error) {length := len(args[0].(string))return length, nil},}exprString := "strlen('teststring')"expr, _ := govaluate.NewEvaluableExpressionWithFunctions(exprString, functions)result, _ := expr.Evaluate(nil)fmt.Println(result) // 10}
支持的操作和类型
govaluate支持的操作和类型与 Go 语言有些不同。一方面govaluate中的类型和操作不如 Go 丰富,另一方面govaluate也对一些操作进行了扩展。
算数、比较和逻辑运算:
+``-``/``*``&``|``^``**``%``>>``<<:加减乘除,按位与,按位或,异或,乘方,取模,左移和右移;>``>=``<``<=``==``!=``=~``!~:=~为正则匹配,!~为正则不匹配;||``&&:逻辑或和逻辑与。
常量:
- 数字常量,
govaluate中将数字都作为 64 位浮点数处理; - 字符串常量,注意在
govaluate中,字符串用单引号'; - 日期时间常量,格式与字符串相同,
govaluate会尝试自动解析字符串是否是日期,只支持 RFC3339、ISO8601等有限的格式; - 布尔常量:
true、false。
其他:
- 圆括号可以改变计算优先级;
- 数组定义在
()中,每个元素之间用,分隔,可以支持任意的元素类型,如(1, 2, 'foo')。实际上在govaluate中数组是用[]interface{}来表示的; - 三目运算符:
? :。
