diff --git a/README.md b/README.md index 221eb5d..3d427aa 100644 --- a/README.md +++ b/README.md @@ -598,6 +598,8 @@ import "github.com/duke-git/lancet/v2/maputil" #### Function list: +- **MapTo** : quick map any value to struct or any base type. + [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapTo)] - **ForEach** : executes iteratee funcation for every key and value pair in map. [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ForEach)] [[play](https://go.dev/play/p/OaThj6iNVXK)] @@ -1340,51 +1342,6 @@ import "github.com/duke-git/lancet/v2/xerror" [[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#TryUnwrap)] [[play](https://go.dev/play/p/acyZVkNZEeW)] -### 22. quick map any to struct or any base type -```go -import "github.com/duke-git/lancet/v2/typemap" -``` -#### Example -```go -type ( - Person struct { - Name string `json:"name"` - Age int `json:"age"` - Phone string `json:"phone"` - Addr Address `json:"address"` - } - - Address struct { - Street string `json:"street"` - Number int `json:"number"` - } -) - -func main() { - v := map[string]interface{}{ - "person":map[string]interface{}{ - "name":"Nothin", - "age":123, - "phone":"123421312", - "address":map[string]interface{}{ - "street":"test", - "number":1, - }, - }, - "other":1234, - } - - var person Person - err :=typemap.MapTo(v["person"],&person) - if err != nil { - //error handler ... - } - - log.Println(person) -} - - -``` ## How to Contribute diff --git a/README_zh-CN.md b/README_zh-CN.md index 2af0bf9..9b0cda2 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -597,6 +597,8 @@ import "github.com/duke-git/lancet/v2/maputil" #### 函数列表: +- **MapTo** : 快速将map或者其他类型映射到结构体或者指定类型。 + [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#MapTo)] - **ForEach** : 对 map 中的每对 key 和 value 执行 iteratee 函数。 [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ForEach)] [[play](https://go.dev/play/p/OaThj6iNVXK)] @@ -1341,52 +1343,6 @@ import "github.com/duke-git/lancet/v2/xerror" [[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#TryUnwrap)] [[play](https://go.dev/play/p/acyZVkNZEeW)] - - -### 22. [typemap] 快速将map或者其他类型映射到结构体或者指定类型 -```go -import "github.com/duke-git/lancet/v2/typemap" -``` -#### Example -```go -type ( - Person struct { - Name string `json:"name"` - Age int `json:"age"` - Phone string `json:"phone"` - Addr Address `json:"address"` - } - - Address struct { - Street string `json:"street"` - Number int `json:"number"` - } -) - -func main() { - v := map[string]interface{}{ - "person":map[string]interface{}{ - "name":"Nothin", - "age":123, - "phone":"123421312", - "address":map[string]interface{}{ - "street":"test", - "number":1, - }, - }, - "other":1234, - } - - var person Person - err :=typemap.MapTo(v["person"],&person) - if err != nil { - //error handler ... - } - - log.Println(person) -} - - ## 如何贡献代码 非常感激任何的代码提交以使 lancet 的功能越来越强大。创建 pull request 时请遵守以下规则。 diff --git a/docs/maputil.md b/docs/maputil.md index e70733e..fbcc6f5 100644 --- a/docs/maputil.md +++ b/docs/maputil.md @@ -22,6 +22,7 @@ import ( ## Index +- [MapTo](#MapTo) - [ForEach](#ForEach) - [Filter](#Filter) - [FilterByKeys](#FilterByKeys) @@ -47,6 +48,64 @@ import ( ## Documentation + +### MapTo + +
Rry to map any interface to struct or base type.
+ +Signature: + +```go +func MapTo(src any, dst any) error +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/maputil" +) + +func main() { + type ( + Person struct { + Name string `json:"name"` + Age int `json:"age"` + Phone string `json:"phone"` + Addr Address `json:"address"` + } + + Address struct { + Street string `json:"street"` + Number int `json:"number"` + } + ) + + personInfo := map[string]interface{}{ + "name": "Nothin", + "age": 28, + "phone": "123456789", + "address": map[string]interface{}{ + "street": "test", + "number": 1, + }, + } + + var p Person + err := MapTo(personInfo, &p) + + fmt.Println(err) + fmt.Println(p) + + // Output: + //Executes iteratee funcation for every key and value pair in map.
@@ -123,7 +182,7 @@ func main() { maputil.Filter(m, func(_ string, value int) { sum += value }) - + result := maputil.Filter(m, isEven) fmt.Println(result) @@ -133,7 +192,6 @@ func main() { } ``` - ### FilterByKeysIterates over map, return a new map whose keys are all given keys.
@@ -172,7 +230,6 @@ func main() { } ``` - ### FilterByValuesIterates over map, return a new map whose values are all given values.
@@ -211,7 +268,6 @@ func main() { } ``` - ### OmitByOmitBy is the opposite of Filter, removes all the map elements for which the predicate function returns true.
@@ -253,7 +309,6 @@ func main() { } ``` - ### OmitByKeysThe opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
@@ -292,7 +347,6 @@ func main() { } ``` - ### OmitByValuesThe opposite of FilterByValues. remov all elements whose value are in the give slice.
@@ -331,7 +385,6 @@ func main() { } ``` - ### IntersectIterates over maps, return a new map of key and value pairs in all given maps.
@@ -419,7 +472,7 @@ func main() { keys := maputil.Keys(m) sort.Ints(keys) - + fmt.Println(keys) // Output: @@ -498,7 +551,7 @@ func main() { "b": 22, "d": 33, } - + result := maputil.Minus(m1, m2) fmt.Println(result) @@ -638,7 +691,6 @@ func main() { } ``` - ### MapKeysTransforms a map to other type map by manipulating it's keys.
@@ -717,7 +769,6 @@ func main() { } ``` - ### EntryTransforms a map into array of key/value pairs.
@@ -763,7 +814,6 @@ func main() { } ``` - ### FromEntriesCreates a map based on a slice of key/value pairs.
@@ -841,7 +891,6 @@ func main() { } ``` - ### IsDisjointChecks two maps are disjoint if they have no keys in common
diff --git a/docs/maputil_zh-CN.md b/docs/maputil_zh-CN.md index 84a713d..dc012c5 100644 --- a/docs/maputil_zh-CN.md +++ b/docs/maputil_zh-CN.md @@ -22,6 +22,7 @@ import ( ## 目录: +- [MapTo](#MapTo) - [ForEach](#ForEach) - [Filter](#Filter) - [FilterByKeys](#FilterByKeys) @@ -47,6 +48,63 @@ import ( ## API 文档: +### MapTo + +快速将map或者其他类型映射到结构体或者指定类型。
+ +函数签名: + +```go +func MapTo(src any, dst any) error +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/maputil" +) + +func main() { + type ( + Person struct { + Name string `json:"name"` + Age int `json:"age"` + Phone string `json:"phone"` + Addr Address `json:"address"` + } + + Address struct { + Street string `json:"street"` + Number int `json:"number"` + } + ) + + personInfo := map[string]interface{}{ + "name": "Nothin", + "age": 28, + "phone": "123456789", + "address": map[string]interface{}{ + "street": "test", + "number": 1, + }, + } + + var p Person + err := MapTo(personInfo, &p) + + fmt.Println(err) + fmt.Println(p) + + // Output: + //对map中的每对key和value执行iteratee函数
@@ -80,7 +138,7 @@ func main() { maputil.ForEach(m, func(_ string, value int) { sum += value }) - + fmt.Println(sum) // Output: @@ -123,7 +181,7 @@ func main() { maputil.Filter(m, func(_ string, value int) { sum += value }) - + result := Filter(m, isEven) fmt.Println(result) @@ -171,7 +229,6 @@ func main() { } ``` - ### FilterByValues迭代map, 返回一个新map,其value都是给定的value值。
@@ -210,7 +267,6 @@ func main() { } ``` - ### OmitByFilter的反向操作, 迭代map中的每对key和value, 删除符合predicate函数的key, value, 返回新map。
@@ -252,7 +308,6 @@ func main() { } ``` - ### OmitByKeysFilterByKeys的反向操作, 迭代map, 返回一个新map,其key不包括给定的key值。
@@ -291,7 +346,6 @@ func main() { } ``` - ### OmitByValuesFilterByValues的反向操作, 迭代map, 返回一个新map,其value不包括给定的value值。
@@ -416,7 +470,7 @@ func main() { keys := maputil.Keys(m) sort.Ints(keys) - + fmt.Println(keys) // Output: @@ -453,7 +507,7 @@ func main() { 1: "1", 3: "2", } - + result := maputil.Merge(m1, m2) fmt.Println(result) @@ -632,7 +686,6 @@ func main() { } ``` - ### MapKeys操作map的每个key,然后转为新的map。
@@ -711,7 +764,6 @@ func main() { } ``` - ### Entry将map转换为键/值对切片。
@@ -757,7 +809,6 @@ func main() { } ``` - ### FromEntries基于键/值对的切片创建map。
diff --git a/go.mod b/go.mod index 1958f5a..9e6c3ae 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,3 @@ require ( golang.org/x/exp v0.0.0-20221208152030-732eee02a75a golang.org/x/text v0.5.0 ) - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.8.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/go.sum b/go.sum index c2121dd..a12ea5d 100644 --- a/go.sum +++ b/go.sum @@ -1,20 +1,4 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw= golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/assert.go b/internal/assert.go index 5f4cd16..d51af3c 100644 --- a/internal/assert.go +++ b/internal/assert.go @@ -5,6 +5,7 @@ package internal import ( + "bytes" "fmt" "reflect" "runtime" @@ -44,6 +45,52 @@ func (a *Assert) NotEqual(expected, actual any) { } } +// EqualValues asserts that two objects are equal or convertable to the same types and equal. +// https://github.com/stretchr/testify/assert/assertions.go +func (a *Assert) EqualValues(expected, actual any) { + if !objectsAreEqualValues(expected, actual) { + makeTestFailed(a.T, a.CaseName, expected, actual) + } +} + +func objectsAreEqualValues(expected, actual interface{}) bool { + if objectsAreEqual(expected, actual) { + return true + } + + actualType := reflect.TypeOf(actual) + if actualType == nil { + return false + } + expectedValue := reflect.ValueOf(expected) + if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { + // Attempt comparison after type conversion + return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) + } + + return false +} + +func objectsAreEqual(expected, actual interface{}) bool { + if expected == nil || actual == nil { + return expected == actual + } + + exp, ok := expected.([]byte) + if !ok { + return reflect.DeepEqual(expected, actual) + } + + act, ok := actual.([]byte) + if !ok { + return false + } + if exp == nil || act == nil { + return exp == nil && act == nil + } + return bytes.Equal(exp, act) +} + // Greater check if expected is greate than actual func (a *Assert) Greater(expected, actual any) { if compare(expected, actual) != compareGreater { diff --git a/maputil/map_example_test.go b/maputil/map_example_test.go index 3909a14..3d9b784 100644 --- a/maputil/map_example_test.go +++ b/maputil/map_example_test.go @@ -397,3 +397,39 @@ func ExampleOmitByValues() { // Output: // map[a:1 b:2 c:3] } + +func ExampleMapTo() { + type ( + Person struct { + Name string `json:"name"` + Age int `json:"age"` + Phone string `json:"phone"` + Addr Address `json:"address"` + } + + Address struct { + Street string `json:"street"` + Number int `json:"number"` + } + ) + + personInfo := map[string]interface{}{ + "name": "Nothin", + "age": 28, + "phone": "123456789", + "address": map[string]interface{}{ + "street": "test", + "number": 1, + }, + } + + var p Person + err := MapTo(personInfo, &p) + + fmt.Println(err) + fmt.Println(p) + + // Output: + //