golang 每日一庫之參數校驗工具 go-tagexpr
go-tagexpr 是字節跳動開源的一款輕量級 Go 標籤解析與表達式求值引擎。
我一般用來校驗參數。
它的主要功能是支持通過結構體標籤(struct tag)定義表達式,然後在運行時動態解析這些表達式,實現靈活的數據校驗、默認值設置等功能。
核心特性
示例
type User struct {
Name string `json:"name" tagexpr:"len(name) > 0"`
Age int `json:"age" tagexpr:"age >= 18"`
}
u := User{Name: "", Age: 17}
expr := tagexpr.New("tagexpr")
err := expr.Validate(&u)
上例中,Name 不能爲空字符串,Age 必須大於等於 18。Validate 方法會自動解析 tagexpr 標籤中的表達式,並在不滿足條件時返回錯誤。
示例 2
package tagexpr_test
import (
"fmt"
tagexpr "github.com/bytedance/go-tagexpr/v2"
)
func Example() {
type T struct {
A int `tagexpr:"$<0||$>=100"`
B string `tagexpr:"len($)>1 && regexp('^\\w*$')"`
C bool `tagexpr:"expr1:(f.g)$>0 && $; expr2:'C must be true when T.f.g>0'"`
d []string `tagexpr:"@:len($)>0 && $[0]=='D'; msg:sprintf('invalid d: %v',$)"`
e map[string]int `tagexpr:"len($)==$['len']"`
e2 map[string]*int `tagexpr:"len($)==$['len']"`
f struct {
g int `tagexpr:"$"`
}
h int `tagexpr:"$>minVal"`
}
vm := tagexpr.New("tagexpr")
t := &T{
A: 107,
B: "abc",
C: true,
d: []string{"x", "y"},
e: map[string]int{"len": 1},
e2: map[string]*int{"len": new(int)},
f: struct {
g int `tagexpr:"$"`
}{1},
h: 10,
}
tagExpr, err := vm.Run(t)
if err != nil {
panic(err)
}
fmt.Println(tagExpr.Eval("A"))
fmt.Println(tagExpr.Eval("B"))
fmt.Println(tagExpr.Eval("C@expr1"))
fmt.Println(tagExpr.Eval("C@expr2"))
if !tagExpr.Eval("d").(bool) {
fmt.Println(tagExpr.Eval("d@msg"))
}
fmt.Println(tagExpr.Eval("e"))
fmt.Println(tagExpr.Eval("e2"))
fmt.Println(tagExpr.Eval("f.g"))
fmt.Println(tagExpr.EvalWithEnv("h", map[string]interface{}{"minVal": 9}))
fmt.Println(tagExpr.EvalWithEnv("h", map[string]interface{}{"minVal": 11}))
// Output:
// true
// true
// true
// C must be true when T.f.g>0
// invalid d: [x y]
// true
// false
// 1
// true
// false
}
在 gin 中使用
import (
"github.com/bytedance/go-tagexpr/v2"
"github.com/gin-gonic/gin"
"net/http"
)
var expr = tagexpr.New("tagexpr")
func RegisterHandler(c *gin.Context) {
var req RegisterReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "請求參數不合法"})
return
}
if err := expr.Validate(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "註冊成功"})
}
支持的表達式
-
常用邏輯:
&&,||,! -
數值比較:
==,!=,<,<=,>,>= -
字符串函數:
len(str),hasPrefix,hasSuffix,contains等 -
空值檢查:
isNil,notNil
支持對結構體字段進行調用與組合邏輯判斷,功能接近模板語言的表達式系統。
應用場景
- 就不細說了吧
性能如何
go-tagexpr 在表達式編譯時採用緩存機制,避免重複解析,提高了執行效率,
官方 benchmark 中表現良好,特別適合高併發業務校驗場景。
標題:golang 每日一庫之 go-tagexpr
作者:mooncakeee
地址:http://blog.dd95828.com/articles/2025/06/26/1750915451642.html
聯繫:scotttu@163.com
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Hhm3VIo20c2Z_zE856o_Aw