diff options
| author | Shulhan <ms@kilabit.info> | 2022-06-01 22:11:10 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2022-06-01 22:11:10 +0700 |
| commit | f28f3cbe2b10e538fd79ac9aa6cd271b5a17acbd (patch) | |
| tree | cbbe4f8db0e23f96d180c419261274f0dcf2db6e | |
| parent | 907dde170237198446a1dcbdee4964dac13fede0 (diff) | |
| download | pakakeh.go-f28f3cbe2b10e538fd79ac9aa6cd271b5a17acbd.tar.xz | |
lib/reflect: add function Tag to simplify lookup on struct's field tag
Given a StructField and the name of tag, return the tag's value and
options inside the tag.
The options is any string after tag's value, separated by comma.
For example, given the following field definition
F `tag:"name,opt1, opt2"`
It will return (name, [opt1 opt2], true).
If the field is exported but does not have tag, it will return the field
name (as is without converting to lower case) in val with hasTag is
false: (Name, nil, false).
If the field is un-exported it will return empty val with hasTag is
false ("", nil, false).
| -rw-r--r-- | lib/reflect/reflect.go | 51 | ||||
| -rw-r--r-- | lib/reflect/reflect_example_test.go | 33 |
2 files changed, 84 insertions, 0 deletions
diff --git a/lib/reflect/reflect.go b/lib/reflect/reflect.go index b8dba25d..4b22d3d9 100644 --- a/lib/reflect/reflect.go +++ b/lib/reflect/reflect.go @@ -8,6 +8,7 @@ package reflect import ( "fmt" "reflect" + "strings" "unsafe" ) @@ -59,6 +60,56 @@ func IsNil(v interface{}) bool { return v == nil } +// Tag simplify lookup on struct's field tag. +// +// Given a StructField and the name of tag, return the tag's value and +// options inside the tag. +// The options is any string after tag's value, separated by comma. +// For example, given the following field definition +// +// F `tag:"name,opt1, opt2"` +// +// It will return (name, [opt1 opt2], true). +// +// If the field is exported but does not have tag, it will return the field +// name (as is without converting to lower case) in val with hasTag is false: +// (Name, nil, false). +// +// If the field is unexported it will return empty val with hasTag is false +// ("", nil, false). +func Tag(field reflect.StructField, tag string) (val string, opts []string, hasTag bool) { + if len(field.PkgPath) != 0 { + // field is unexported. + return "", nil, false + } + + var ( + x int + ) + + val, hasTag = field.Tag.Lookup(tag) + if !hasTag { + // Tag not defined, so we use field name as key. + val = field.Name + } else { + opts = strings.Split(val, ",") + for x, val = range opts { + opts[x] = strings.TrimSpace(val) + } + + val = opts[0] + opts = opts[1:] + if len(val) == 0 { + // Tag is empty, use field name as key and + // mark it as not OK. + val = field.Name + hasTag = false + } + } + + return val, opts, hasTag +} + // doEqual compare two kind of objects and return nils if both are equal. // // If its not equal, it will return the interface{} value of v1 and v2 and diff --git a/lib/reflect/reflect_example_test.go b/lib/reflect/reflect_example_test.go index 58e6d1cc..f0919a6f 100644 --- a/lib/reflect/reflect_example_test.go +++ b/lib/reflect/reflect_example_test.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "net/http" + "reflect" ) type F func() @@ -70,3 +71,35 @@ func ExampleIsNil() { // *errors.errorString: v == nil is false, IsNil() is false // <nil>: v == nil is true, IsNil() is true } + +func ExampleTag() { + type T struct { + F1 int `atag:" f1 , opt1 , opt2 ,"` + F2 int `atag:", opt1"` + F3 int + f4 int + } + + var ( + t T + vtype reflect.Type + field reflect.StructField + val string + opts []string + x int + hasTag bool + ) + + vtype = reflect.TypeOf(t) + + for x = 0; x < vtype.NumField(); x++ { + field = vtype.Field(x) + val, opts, hasTag = Tag(field, "atag") + fmt.Printf("%q %v %v\n", val, opts, hasTag) + } + //Output: + //"f1" [opt1 opt2 ] true + //"F2" [opt1] false + //"F3" [] false + //"" [] false +} |
