diff --git a/convertor/convertor.go b/convertor/convertor.go index 80f9f92..c5373be 100644 --- a/convertor/convertor.go +++ b/convertor/convertor.go @@ -11,7 +11,7 @@ import ( "encoding/json" "errors" "fmt" - "github.com/duke-git/lancet/v2/structutil" + "github.com/duke-git/lancet/v2/structs" "math" "reflect" "strconv" @@ -235,7 +235,7 @@ func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K // map key is specified same as struct field tag `json` value. // Play: https://go.dev/play/p/KYGYJqNUBOI func StructToMap(value any) (map[string]any, error) { - return structutil.ToMap(value) + return structs.ToMap(value) } // MapToSlice convert map to slice based on iteratee function. diff --git a/docs/structutil/field.md b/docs/structs/field.md similarity index 100% rename from docs/structutil/field.md rename to docs/structs/field.md diff --git a/docs/structs/field_zh-CN.md b/docs/structs/field_zh-CN.md new file mode 100644 index 0000000..03e23a1 --- /dev/null +++ b/docs/structs/field_zh-CN.md @@ -0,0 +1,353 @@ +# Field + +Field 包封装了一个抽象的`Field`结构体,提供了操作`struct`属性的相关函数 + +
+ +## 源码: + +- [https://github.com/duke-git/lancet/blob/main/structs/field.go](https://github.com/duke-git/lancet/blob/main/structs/field.go) + +
+ +## 用法: + +```go +import ( + "github.com/duke-git/lancet/v2/structs" +) +``` + +
+ +## 目录: +- [Tag](#Tag) +- [Name](#Name) +- [Value](#Value) +- [Kind](#Kind) +- [IsEmbedded](#IsEmbedded) +- [IsExported](#IsExported) +- [IsZero](#IsZero) +- [IsSlice](#IsSlice) + +> 注意:由于`Field`继承于`Struct`,所以同样拥有`Struct`所有方法,如下: + +- [ToMap](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#ToMap) +- [Fields](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN#Fields) +- [Field](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN#Field) +- [IsStruct](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN#IsStruct) + +
+ +## API 文档: + +### Tag + +

获取`Field`的`Tag`,默认的tag key是json

+ +函数签名: + +```go +func (f *Field) Tag() *Tag +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type Parent struct { + Name string `json:"name,omitempty"` + } + p1 := &Parent{"111"} + + s := structs.New(p1) + n, _ := s.Field("Name") + tag := n.Tag() + + fmt.Println(tag.Name) + + // Output: + // name +} +``` + +### Value + +

获取`Field`属性的值

+ +函数签名: + +```go +func (f *Field) Value() any +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type Parent struct { + Name string `json:"name,omitempty"` + } + p1 := &Parent{"111"} + + s := structs.New(p1) + n, _ := s.Field("Name") + + fmt.Println(n.Value()) + + // Output: + // 111 +} +``` + +### IsEmbedded + +

判断属性是否为嵌入

+ +函数签名: + +```go +func (f *Field) IsEmbedded() bool +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type Parent struct { + Name string + } + type Child struct { + Parent + Age int + } + c1 := &Child{} + c1.Name = "111" + c1.Age = 11 + + s := structs.New(c1) + n, _ := s.Field("Name") + a, _ := s.Field("Age") + + fmt.Println(n.IsEmbedded()) + fmt.Println(a.IsEmbedded()) + + // Output: + // true + // false +} +``` + +### IsExported + +

判断属性是否导出

+ +函数签名: + +```go +func (f *Field) IsExported() bool +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type Parent struct { + Name string + age int + } + p1 := &Parent{Name: "11", age: 11} + s := structs.New(p1) + n, _ := s.Field("Name") + a, _ := s.Field("age") + + fmt.Println(n.IsExported()) + fmt.Println(a.IsExported()) + + // Output: + // true + // false +} +``` + +### IsZero + +

判断属性是否为零值

+ +函数签名: + +```go +func (f *Field) IsZero() bool +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type Parent struct { + Name string + Age int + } + p1 := &Parent{Age: 11} + s := structs.New(p1) + n, _ := s.Field("Name") + a, _ := s.Field("Age") + + fmt.Println(n.IsZero()) + fmt.Println(a.IsZero()) + + // Output: + // true + // false +} +``` + +### Name + +

获取属性名

+ +函数签名: + +```go +func (f *Field) Name() string +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type Parent struct { + Name string + Age int + } + p1 := &Parent{Age: 11} + s := structs.New(p1) + n, _ := s.Field("Name") + a, _ := s.Field("Age") + + fmt.Println(n.Name()) + fmt.Println(a.Name()) + + // Output: + // Name + // Age +} +``` + +### Kind + +

获取属性Kind

+ +函数签名: + +```go +func (f *Field) Kind() reflect.Kind +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type Parent struct { + Name string + Age int + } + p1 := &Parent{Age: 11} + s := structs.New(p1) + n, _ := s.Field("Name") + a, _ := s.Field("Age") + + fmt.Println(n.Kind()) + fmt.Println(a.Kind()) + + // Output: + // string + // int +} +``` + +### IsSlice + +

判断属性是否是切片

+ +函数签名: + +```go +func (f *Field) IsSlice() bool +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type Parent struct { + Name string + arr []int + } + + p1 := &Parent{arr: []int{1, 2, 3}} + s := structs.New(p1) + a, _ := s.Field("arr") + + fmt.Println(a.IsSlice()) + + // Output: + // true +} +``` \ No newline at end of file diff --git a/docs/structs/struct.md b/docs/structs/struct.md new file mode 100644 index 0000000..76a390a --- /dev/null +++ b/docs/structs/struct.md @@ -0,0 +1,2 @@ +# Structs + diff --git a/docs/structs/struct_zh-CN.md b/docs/structs/struct_zh-CN.md new file mode 100644 index 0000000..166f12b --- /dev/null +++ b/docs/structs/struct_zh-CN.md @@ -0,0 +1,212 @@ +# Structs + +structs 包封装了一个抽象的`Struct`结构体,提供了操作`struct`的相关函数 + +
+ +## 源码: + +- [https://github.com/duke-git/lancet/blob/main/structs/struct.go](https://github.com/duke-git/lancet/blob/main/structs/struct.go) + +
+ +## 用法: + +```go +import ( + "github.com/duke-git/lancet/v2/structs" +) +``` + +
+ +## 目录: +- [New](#New) +- [ToMap](#ToMap) +- [Fields](#Fields) +- [Field](#Field) +- [IsStruct](#IsStruct) + +
+ +## API 文档: + +### New + +

`Struct`结构体的构造函数

+ +函数签名: + +```go +func New(value any, tagName ...string) *Struct +``` + +示例: + +```go +package main + +import ( + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type People struct { + Name string `json:"name"` + } + p1 := &People{Name: "11"} + s := structs.New(p1) + // to do something +} +``` + +### ToMap + +

将一个合法的struct对象转换为map[string]any

+ +函数签名: + +```go +func (s *Struct) ToMap() (map[string]any, error) +``` + +除此之外,提供一个便捷的静态方法ToMap + +```go +func ToMap(v any) (map[string]any, error) +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type People struct { + Name string `json:"name"` + } + p1 := &People{Name: "11"} + s1 := structs.New(p1) + m1, _ := s1.ToMap() + + fmt.Println(m1) + + // 如果不需要Struct更多的方法,可以直接使用ToMap + m2, _ := structs.ToMap(p1) + + fmt.Println(m2) + + // Output: + // map[name:11] + // map[name:11] +} +``` + +### Fields + +

获取一个struct对象的属性列表

+ +函数签名: + +```go +func (s *Struct) Fields() []*Field +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type People struct { + Name string `json:"name"` + } + p1 := &People{Name: "11"} + s := structs.New(p1) + fields := s.Fields() + + fmt.Println(len(fields)) + + // Output: + // 1 +} +``` + +### Field + +

根据属性名获取一个struct对象的属性

+ +函数签名: + +```go +func (s *Struct) Field(name string) *Field +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type People struct { + Name string `json:"name"` + } + p1 := &People{Name: "11"} + s := structs.New(p1) + f := s.Field("Name") + + fmt.Println(f.Value()) + + // Output: + // 11 +} +``` + +### IsStruct + +

判断是否为一个合法的struct对象

+ +函数签名: + +```go +func (s *Struct) IsStruct() bool +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/structs" +) + +func main() { + type People struct { + Name string `json:"name"` + } + p1 := &People{Name: "11"} + s := structs.New(p1) + + fmt.Println(s.IsStruct()) + + // Output: + // true +} +``` diff --git a/docs/structutil/struct.md b/docs/structutil/struct.md deleted file mode 100644 index e69de29..0000000 diff --git a/structutil/field.go b/structs/field.go similarity index 90% rename from structutil/field.go rename to structs/field.go index 6be4f70..893c5fa 100644 --- a/structutil/field.go +++ b/structs/field.go @@ -1,4 +1,4 @@ -package structutil +package structs import ( "reflect" @@ -20,6 +20,7 @@ func newField(v reflect.Value, f reflect.StructField, tagName string) *Field { tag: newTag(tag), } field.rvalue = v + field.rtype = v.Type() field.TagName = tagName return field } @@ -67,8 +68,8 @@ func (f *Field) IsSlice() bool { return k == reflect.Slice } -// MapValue conver field value to map. -func (f *Field) MapValue(value any) any { +// mapValue covert field value to map +func (f *Field) mapValue(value any) any { val := pointer.ExtractPointer(value) v := reflect.ValueOf(val) var ret any @@ -86,7 +87,7 @@ func (f *Field) MapValue(value any) any { // iterate the map m := make(map[string]any, v.Len()) for _, key := range v.MapKeys() { - m[key.String()] = f.MapValue(v.MapIndex(key).Interface()) + m[key.String()] = f.mapValue(v.MapIndex(key).Interface()) } ret = m default: @@ -98,7 +99,7 @@ func (f *Field) MapValue(value any) any { case reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice, reflect.Chan: slices := make([]any, v.Len()) for i := 0; i < v.Len(); i++ { - slices[i] = f.MapValue(v.Index(i).Interface()) + slices[i] = f.mapValue(v.Index(i).Interface()) } ret = slices default: diff --git a/structutil/field_test.go b/structs/field_test.go similarity index 94% rename from structutil/field_test.go rename to structs/field_test.go index 8663a27..2c006ec 100644 --- a/structutil/field_test.go +++ b/structs/field_test.go @@ -1,4 +1,4 @@ -package structutil +package structs import ( "github.com/duke-git/lancet/v2/internal" @@ -152,7 +152,7 @@ func TestField_MapValue(t *testing.T) { s := New(p1) f, ok := s.Field("Child") - val := f.MapValue(f.Value()) + val := f.mapValue(f.Value()) assert.Equal(true, ok) assert.Equal(map[string]any{"name": "11-1"}, val) @@ -176,7 +176,7 @@ func TestField_MapValue(t *testing.T) { s := New(p1) f, ok := s.Field("Child") - val := f.MapValue(f.Value()) + val := f.mapValue(f.Value()) assert.Equal(true, ok) assert.Equal(map[string]any{"name": "11-1"}, val) @@ -195,13 +195,13 @@ func TestField_MapValue(t *testing.T) { s := New(p1) f, ok := s.Field("Child") - val := f.MapValue(f.Value()) + val := f.mapValue(f.Value()) assert.Equal(true, ok) assert.Equal([]int{1, 2, 3}, val) }) - t.Run("nested array in struct", func(t *testing.T) { + t.Run("nested array struct", func(t *testing.T) { type Child struct { Name string `json:"name"` } @@ -220,14 +220,14 @@ func TestField_MapValue(t *testing.T) { s := New(p1) f, ok := s.Field("Child") - val := f.MapValue(f.Value()) + val := f.mapValue(f.Value()) assert.Equal(true, ok) arr := []any{map[string]any{"name": "11-1"}, map[string]any{"name": "11-2"}} assert.Equal(arr, val) }) - t.Run("nested ptr array in struct", func(t *testing.T) { + t.Run("nested ptr array struct", func(t *testing.T) { type Child struct { Name string `json:"name"` } @@ -246,7 +246,7 @@ func TestField_MapValue(t *testing.T) { s := New(p1) f, ok := s.Field("Child") - val := f.MapValue(f.Value()) + val := f.mapValue(f.Value()) assert.Equal(true, ok) arr := []any{map[string]any{"name": "11-1"}, map[string]any{"name": "11-2"}} @@ -265,7 +265,7 @@ func TestField_MapValue(t *testing.T) { s := New(p1) f, ok := s.Field("Child") - val := f.MapValue(f.Value()) + val := f.mapValue(f.Value()) assert.Equal(true, ok) assert.Equal(map[string]any{"a": 1, "b": map[string]any{"name": "11-1"}}, val) }) diff --git a/structutil/struct.go b/structs/struct.go similarity index 90% rename from structutil/struct.go rename to structs/struct.go index 914491f..9be9958 100644 --- a/structutil/struct.go +++ b/structs/struct.go @@ -1,4 +1,4 @@ -package structutil +package structs import ( "reflect" @@ -6,7 +6,7 @@ import ( "github.com/duke-git/lancet/v2/pointer" ) -// DefaultTagName is the default tag for struct fields to lookup. +// defaultTagName is the default tag for struct fields to lookup. var defaultTagName = "json" // Struct is abstract struct for provide several high level functions @@ -29,7 +29,7 @@ func New(value any, tagName ...string) *Struct { tn = tagName[0] } - // if need: can also set defaultTagName to tn across structutil package level + // if need: can also set defaultTagName to tn across structs package level // defaultTagName = tn return &Struct{ @@ -57,7 +57,7 @@ func New(value any, tagName ...string) *Struct { // // custom map key // Name string `json:"myName"` // -// ToMap conver the exported fields of a struct to map. +// ToMap convert the exported fields of a struct to map. func (s *Struct) ToMap() (map[string]any, error) { if !s.IsStruct() { return nil, errInvalidStruct(s) @@ -72,7 +72,7 @@ func (s *Struct) ToMap() (map[string]any, error) { if f.IsZero() && f.tag.HasOption("omitempty") { continue } - result[f.tag.Name] = f.MapValue(f.Value()) + result[f.tag.Name] = f.mapValue(f.Value()) } return result, nil diff --git a/structutil/struct_internal.go b/structs/struct_internal.go similarity index 83% rename from structutil/struct_internal.go rename to structs/struct_internal.go index ada0dd2..bc147cc 100644 --- a/structutil/struct_internal.go +++ b/structs/struct_internal.go @@ -1,4 +1,4 @@ -package structutil +package structs import "fmt" diff --git a/structutil/struct_test.go b/structs/struct_test.go similarity index 97% rename from structutil/struct_test.go rename to structs/struct_test.go index eb64b61..0cfabed 100644 --- a/structutil/struct_test.go +++ b/structs/struct_test.go @@ -1,4 +1,4 @@ -package structutil +package structs import ( "reflect" @@ -10,7 +10,7 @@ import ( func TestStruct_ToMap(t *testing.T) { assert := internal.NewAssert(t, "TestStruct_ToMap") - t.Run("no struct", func(t *testing.T) { + t.Run("invalid struct", func(t *testing.T) { m, _ := ToMap(1) var expected map[string]any assert.Equal(expected, m) @@ -21,7 +21,7 @@ func TestStruct_ToMap(t *testing.T) { Name string `json:"name"` age int } - p := People{ + p := &People{ "test", 100, } diff --git a/structutil/tag.go b/structs/tag.go similarity index 96% rename from structutil/tag.go rename to structs/tag.go index cd9f34c..2bf9917 100644 --- a/structutil/tag.go +++ b/structs/tag.go @@ -1,4 +1,4 @@ -package structutil +package structs import ( "strings"