引言
今天给大家介绍一个比较好玩的库,今天在看别人写的代码的时候发现在代码中用到了govaluate库,这个库可以让我们在golang代码中计算一个表达式的结果,这让我们在实现一些条件判断业务场景的时候非常便利。govaluate与 JavaScript 中的eval功能类似,用于计算任意表达式的值。
此类功能函数在 JavaScript/Python 等动态语言中比较常见。govaluate让 Go 这个编译型语言也有了这个能力!
快速使用
安装
$ go get github.com/Knetic/govaluate
使用
package main
import (
"fmt"
"github.com/Knetic/govaluate"
"log"
)
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)
}
使用govaluate计算表达式只需要两步:
调用NewEvaluableExpression()将表达式转为一个表达式对象; 调用表达式对象的Evaluate方法,传入参数,返回表达式的值。 上面演示了一个很简单的例子,我们使用govaluate计算10 > 0的值,该表达式不需要参数,故传给Evaluate()方法nil值。当然,这个例子并不实用,显然我们直接在代码中计算10 > 0更简单。但问题是,有些时候我们并不知道需要计算的表达式的所有信息,甚至我们都不知道表达式的结构。这时govaluate的作用就体现出来了。
参数
govaluate支持在表达式中使用参数,调用表达式对象的Evaluate()方法时通过map[string]interface{}类型将参数传入计算。其中map的键为参数名,值为参数值。例如:
package main
import (
"fmt"
"github.com/Knetic/govaluate"
)
func main() {
expr1, _ := govaluate.NewEvaluableExpression("foo >0")
param:= make(map[string]interface{})
param["foo"] = -1
r1, _ := expr1.Evaluate(param)
fmt.Printf("r1:%+v\n",r1)
expr2, _ := govaluate.NewEvaluableExpression("a * b")
param1 := make(map[string]interface{})
param1["a"] = 2
param1["b"] =4
r2,_:= expr2.Evaluate(param1)
fmt.Printf("r2:%+v",r2)
expr3, _ := govaluate.NewEvaluableExpression("(a / b) * 100")
param3 := make(map[string]interface{})
param3["a"] = 1024
param3["b"] = 512
r3,_:= expr3.Evaluate(param3)
fmt.Printf("r3:%+v",r3)
}
一次编译,多次运行 使用带参数的表达式,我们可以实现一个表达式的一次“编译”,多次运行。只需要使用编译返回的表达式对象即可,可多次调用其Evaluate()方法:
package main
import (
"fmt"
"github.com/Knetic/govaluate"
)
func main() {
expr2, _ := govaluate.NewEvaluableExpression("a * b")
param1 := make(map[string]interface{})
param1["a"] = 2
param1["b"] =4
r2,_:= expr2.Evaluate(param1)
fmt.Printf("r2:%+v",r2)
param2 := make(map[string]interface{})
param2["a"] = 5
param2["b"] =6
r23,_:= expr2.Evaluate(param2)
fmt.Printf("r223:%+v",r23)
}
上面的代码的运行结果,第一次运行 根据传递的参数得到的结果是8,第二次运行,由于我们更换了参数,但是还是复用了【a*b】的表达式,所以结果是30。
函数 如果仅仅能进行常规的算数和逻辑运算,govaluate的功能会大打折扣。govaluate提供了自定义函数的功能。所有自定义函数需要先定义好,存入一个map[string]govaluate.ExpressionFunction变量中,然后调用govaluate.NewEvaluableExpressionWithFunctions()生成表达式,此表达式中就可以使用这些函数了。自定义函数类型为func (args ...interface{}) (interface{}, error),如果函数返回错误,则这个表达式求值返回错误。
总结
govaluate虽然支持的操作和类型有限,也能实现比较有意思的功能。例如,可以写一个 Web 服务,由用户自己编写表达式,设置参数,服务器算出结果。