github.com/bytedance/go-tagexpr/v2@v2.9.8/README.md (about) 1 # go-tagexpr [](http://goreportcard.com/report/bytedance/go-tagexpr) [](http://godoc.org/github.com/bytedance/go-tagexpr) 2 3 An interesting go struct tag expression syntax for field validation, etc. 4 5 ## Usage 6 7 - **[Validator](https://github.com/bytedance/go-tagexpr/tree/master/validator)**: A powerful validator that supports struct tag expression 8 9 - **[Binding](https://github.com/bytedance/go-tagexpr/tree/master/binding)**: A powerful HTTP request parameters binder that supports struct tag expression 10 11 ## Feature 12 13 - Support for a variety of common operator 14 - Support for accessing arrays, slices, members of the dictionary 15 - Support access to any field in the current structure 16 - Support access to nested fields, non-exported fields, etc. 17 - Support registers function expression 18 - Built-in len, sprintf, regexp functions 19 - Support single mode and multiple mode to define expression 20 - Parameter check subpackage 21 - Use offset pointers to directly take values, better performance 22 - Required go version ≥1.9 23 24 ## Example 25 26 ```go 27 package tagexpr_test 28 29 import ( 30 "fmt" 31 32 tagexpr "github.com/bytedance/go-tagexpr/v2" 33 ) 34 35 func Example() { 36 type T struct { 37 A int `tagexpr:"$<0||$>=100"` 38 B string `tagexpr:"len($)>1 && regexp('^\\w*$')"` 39 C bool `tagexpr:"expr1:(f.g)$>0 && $; expr2:'C must be true when T.f.g>0'"` 40 d []string `tagexpr:"@:len($)>0 && $[0]=='D'; msg:sprintf('invalid d: %v',$)"` 41 e map[string]int `tagexpr:"len($)==$['len']"` 42 e2 map[string]*int `tagexpr:"len($)==$['len']"` 43 f struct { 44 g int `tagexpr:"$"` 45 } 46 } 47 48 vm := tagexpr.New("tagexpr") 49 t := &T{ 50 A: 107, 51 B: "abc", 52 C: true, 53 d: []string{"x", "y"}, 54 e: map[string]int{"len": 1}, 55 e2: map[string]*int{"len": new(int)}, 56 f: struct { 57 g int `tagexpr:"$"` 58 }{1}, 59 } 60 61 tagExpr, err := vm.Run(t) 62 if err != nil { 63 panic(err) 64 } 65 66 fmt.Println(tagExpr.Eval("A")) 67 fmt.Println(tagExpr.Eval("B")) 68 fmt.Println(tagExpr.Eval("C@expr1")) 69 fmt.Println(tagExpr.Eval("C@expr2")) 70 if !tagExpr.Eval("d").(bool) { 71 fmt.Println(tagExpr.Eval("d@msg")) 72 } 73 fmt.Println(tagExpr.Eval("e")) 74 fmt.Println(tagExpr.Eval("e2")) 75 fmt.Println(tagExpr.Eval("f.g")) 76 77 // Output: 78 // true 79 // true 80 // true 81 // C must be true when T.f.g>0 82 // invalid d: [x y] 83 // true 84 // false 85 // 1 86 } 87 ``` 88 89 ## Syntax 90 91 Struct tag syntax spec: 92 93 ``` 94 type T struct { 95 // Single model 96 Field1 T1 `tagName:"expression"` 97 // Multiple model 98 Field2 T2 `tagName:"exprName:expression; [exprName2:expression2;]..."` 99 // Omit it 100 Field3 T3 `tagName:"-"` 101 // Omit it when it is nil 102 Field4 T4 `tagName:"?"` 103 ... 104 } 105 ``` 106 107 NOTE: **The `exprName` under the same struct field cannot be the same!** 108 109 |Operator or Operand|Explain| 110 |-----|---------| 111 |`true` `false`|boolean| 112 |`0` `0.0`|float64 "0"| 113 |`''`|String| 114 |`\\'`| Escape `'` delims in string| 115 |`\"`| Escape `"` delims in string| 116 |`nil`|nil, undefined| 117 |`!`|not| 118 |`+`|Digital addition or string splicing| 119 |`-`|Digital subtraction or negative| 120 |`*`|Digital multiplication| 121 |`/`|Digital division| 122 |`%`|division remainder, as: `float64(int64(a)%int64(b))`| 123 |`==`|`eq`| 124 |`!=`|`ne`| 125 |`>`|`gt`| 126 |`>=`|`ge`| 127 |`<`|`lt`| 128 |`<=`|`le`| 129 |`&&`|Logic `and`| 130 |`\|\|`|Logic `or`| 131 |`()`|Expression group| 132 |`(X)$`|Struct field value named X| 133 |`(X.Y)$`|Struct field value named X.Y| 134 |`$`|Shorthand for `(X)$`, omit `(X)` to indicate current struct field value| 135 |`(X)$['A']`|Map value with key A or struct A sub-field in the struct field X| 136 |`(X)$[0]`|The 0th element or sub-field of the struct field X(type: map, slice, array, struct)| 137 |`len((X)$)`|Built-in function `len`, the length of struct field X| 138 |`mblen((X)$)`|the length of string field X (character number)| 139 |`regexp('^\\w*$', (X)$)`|Regular match the struct field X, return boolean| 140 |`regexp('^\\w*$')`|Regular match the current struct field, return boolean| 141 |`sprintf('X value: %v', (X)$)`|`fmt.Sprintf`, format the value of struct field X| 142 |`range(KvExpr, forEachExpr)`|Iterate over an array, slice, or dictionary <br> - `#k` is the element key var <br> - `#v` is the element value var <br> - `##` is the number of elements <br> - e.g. [example](spec_range_test.go)| 143 |`in((X)$, enum_1, ...enum_n)`|Check if the first parameter is one of the enumerated parameters| 144 145 <!-- |`(X)$k`|Traverse each element key of the struct field X(type: map, slice, array)| 146 |`(X)$v`|Traverse each element value of the struct field X(type: map, slice, array)| --> 147 148 <!-- |`&`|Integer bitwise `and`| 149 |`\|`|Integer bitwise `or`| 150 |`^`|Integer bitwise `not` or `xor`| 151 |`&^`|Integer bitwise `clean`| 152 |`<<`|Integer bitwise `shift left`| 153 |`>>`|Integer bitwise `shift right`| --> 154 155 Operator priority(high -> low): 156 157 * `()` `!` `bool` `float64` `string` `nil` 158 * `*` `/` `%` 159 * `+` `-` 160 * `<` `<=` `>` `>=` 161 * `==` `!=` 162 * `&&` 163 * `||` 164 165 ## Field Selector 166 167 ``` 168 field_lv1.field_lv2...field_lvn 169 ``` 170 171 ## Expression Selector 172 173 - If expression is **single model** or exprName is `@`: 174 175 ``` 176 field_lv1.field_lv2...field_lvn 177 ``` 178 179 - If expression is **multiple model** and exprName is not `@`: 180 181 ``` 182 field_lv1.field_lv2...field_lvn@exprName 183 ``` 184 185 ## Benchmark 186 187 ``` 188 goos: darwin 189 goarch: amd64 190 pkg: github.com/bytedance/go-tagexpr 191 BenchmarkTagExpr-4 10000000 148 ns/op 32 B/op 3 allocs/op 192 BenchmarkReflect-4 10000000 182 ns/op 16 B/op 2 allocs/op 193 PASS 194 ``` 195 196 [Go to test code](https://github.com/bytedance/go-tagexpr/blob/master/tagexpr_test.go#L9-L56)